0

カスタム UserControl で DataBinding を使用すると、奇妙な問題が発生します。私の UserControl "UserControl1" には、UserControl1 内のラベルの内容を設定する依存関係プロパティ LabelText があります。さらに、コマンド「MyCommand」をバインドするボタンがあります。このコマンドはメッセージ ボックスを表示するだけで、UserControl1ViewModel に実装されています。

MainWindow で UserControl1 を使用し、そのビュー モデル (MainWindowViewModel) もある場合、LabelTextFromMainWindow へのバインドを使用して MainWindow.xaml で UserControl の LabelText プロパティを設定したいと思いますが、それを行うと、明示的に指定しない限り、DataContext が間違っています。

この私のコード:

public partial class MainWindow : Window
{
    private MainWindowViewModel vm;

    public MainWindow()
    {
        InitializeComponent();

        DataContext = vm = new MainWindowViewModel();

        vm.LabelTextFromMainWindow = "Hallo";
    }
}

class MainWindowViewModel : System.ComponentModel.INotifyPropertyChanged
{
    #region INotifyPropertyChanged Members

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this,
                new System.ComponentModel.PropertyChangedEventArgs(propertyName));
    }

    #endregion

    private string myLabel;

    public string LabelTextFromMainWindow
    {
        get { return myLabel; }
        set
        {
            myLabel = value;
            OnPropertyChanged("MyLabel");
        }
    }
}

/////////

<UserControl x:Class="WpfApplication1.UserControl1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="224" d:DesignWidth="300">
    <Grid>
        <Button Command="{Binding MyCommand}" Content="Button" Height="55" HorizontalAlignment="Left" Margin="166,99,0,0" Name="button1" VerticalAlignment="Top" Width="104" />
        <Label Margin="30,99,0,0" Name="label1" Height="55" VerticalAlignment="Top" HorizontalAlignment="Left" Width="101" />
    </Grid>
</UserControl>

public partial class UserControl1 : UserControl
{
    private UserControl1ViewModel vm;

    private static UserControl1 instance;

    public UserControl1()
    {
        InitializeComponent();

        instance = this;

        DataContext = vm = new UserControl1ViewModel();
    }

    public string LabelText
    {
        get { return (string)GetValue(LabelProperty); }
        set { SetValue(LabelProperty, value); }
    }

    public static readonly DependencyProperty LabelProperty =
        DependencyProperty.Register("LabelText", typeof(string), typeof(UserControl1), new UIPropertyMetadata(""), OnValidateValueProperty);

    private static bool OnValidateValueProperty(object source)
    {
        if (instance != null)
        {
            instance.label1.Content = source;
        }

        return true;
    }
}

public class UserControl1ViewModel
{
    private DelegateCommand myCommand;

    public ICommand MyCommand
    {
        get
        {
            if (myCommand == null)
                myCommand = new DelegateCommand(new Action<object>(MyExecute),
                    new Predicate<object>(MyCanExecute));
            return myCommand;
        }
    }

    private bool MyCanExecute(object parameter)
    {
        return true;
    }

    private void MyExecute(object parameter)
    {
        MessageBox.Show("Hello World");
    }
}

私のメインウィンドウは次のように記録します:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    xmlns:my="clr-namespace:WpfApplication1">
    <Grid>
        <my:UserControl1 LabelText="{Binding
                                Path=DataContext.LabelTextFromMainWindow,
                                RelativeSource={RelativeSource FindAncestor, 
                                AncestorType={x:Type Window}}}"  
                         HorizontalAlignment="Left"
                         Margin="114,36,0,0"
                         x:Name="userControl11"
                         VerticalAlignment="Top" Height="236" Width="292" />
    </Grid>
</Window>

以下が正しく動作することを期待しました。

LabelText="{Binding Path=LabelTextFromMainWindow}"

ただし、これは書かなければなりません。

LabelText="{Binding Path=DataContext.LabelTextFromMainWindow,
               RelativeSource={RelativeSource FindAncestor, 
                                       AncestorType={x:Type Window}}}"

単純な Binding を適切に機能させるにはどうすればよいですか?

4

1 に答える 1

1

inherits DataContext from its parent設定しない限り、デフォルトで制御しますexplicitly。あなたの場合、 UserControl の DataContext を明示的に設定します

DataContext = vm = new UserControl1ViewModel();

これにより、 UserControl のすべてのバインディングが、UserControl1ViewModelではなくクラスでバインディングを検索しますMainWindowViewModel

RelativeSourceそのため、ウィンドウの DataContext を取得するために使用する必要があります。つまりyou explicitly asked binding to be found in window's DataContext、代わりに独自の DataContext を使用する必要があり、RelativeSource を使用しても問題はありません。

ただし、RelativeSource を使用せずに単純なバインディングのように動作させたい場合は、まずyou need to get rid of explicitly setting DataContextすべてのコマンドとプロパティを移動しMainWindowsViewModelて、UserControl がその DataContext を MainWindow から継承するようにします。

また

ElementNameウィンドウに名前を付けて、 -を使用してバインドできます。

<Window x:Class="WpfApplication1.MainWindow"
        x:Name="MainWindow"> <--- HERE
<Grid>
        <my:UserControl1 LabelText="{Binding
                                       Path=DataContext.LabelTextFromMainWindow, 
                                       ElementName=MainWindow}"/>
于 2013-08-05T17:07:11.870 に答える