web-dev-qa-db-ja.com

WPFユーザーコントロールのデータバインディング

複数のウィンドウで共有される一連のコントロールのUserControlを作成しています。コントロールの1つは、「プロトコル番号」に関して他のプロセスの流れを示すラベルです。

プロトコル番号変数が変更されると、ウィンドウがプロセスの状態を自動的に反映するように、このラベルでDataBindingを提供しようとしています。

これはユーザーコントロールXAMLです。

<UserControl Name="MainOptionsPanel"
    x:Class="ExperienceMainControls.MainControls"
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    >
<Label Height="Auto" Name="numberLabel">Protocol:</Label>
<Label Content="{Binding Path=ProtocolNumber}" Name="protocolNumberLabel"/>
(...)
</UserControl>

これがコードビハインドです。

public partial class MainControls 
{
    public MainControls()
    {
        InitializeComponent();
    }

    public int ProtocolNumber
    {
        get { return (int)GetValue(ProtocolNumberProperty); }
        set { SetValue(ProtocolNumberProperty, value); }
    }

    public static DependencyProperty ProtocolNumberProperty = 
       DependencyProperty.Register("ProtocolNumber", typeof(int), typeof(MainControls));
}

コンストラクターでProtocolNumberを任意の値に設定すると、ユーザーコントロールに反映されるため、これは機能しているようです。

ただし、最後のウィンドウでこのユーザーコントロールを使用すると、データバインディングが壊れます。

XAML:

<Window x:Class="UserControlTesting.Window1"
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml" xmlns:expControl="clr-namespace:ExperienceMainControls;Assembly=ExperienceMainControls"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    >
    <StackPanel>
        <expControl:MainControls ProtocolNumber="{Binding Path=Number, Mode=TwoWay}" />
    </StackPanel>

</Window>

ウィンドウのコードビハインド:

public partial class Window1 : Window
{
    public Window1()
    {
        Number= 15;
        InitializeComponent();
    }

    public int Number { get; set; }
}

これにより、プロトコル番号がゼロに設定され、数値に設定された値は無視されます。

私は例を読んだ

31

出力ウィンドウを見ると、バインディング例外が表示されます。

問題は次のとおりです。ユーザーコントロール内で、ラベルをDataContextではなくユーザーコントロールのDP ProtocolNumberにバインドするため、たとえば要素名をバインドに追加する必要があります。

<UserControl Name="MainOptionsPanel"
    x:Class="ExperienceMainControls.MainControls"
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    x:Name="uc"
    >
<Label Height="Auto" Name="numberLabel">Protocol:</Label>
<Label Content="{Binding Path=ProtocolNumber, ElementName=uc}" Name="protocolNumberLabel"/>
(...)
</UserControl>

編集:いくつかのことをクリアするために、MainWindowのバインディングを変更してもユーザーコントロールが機能します。ただし、RelativeSourceを使用してMainWindowのDataContextにバインドする必要があります。

    <expControl:MainControls ProtocolNumber="{Binding Path=Number, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
39
blindmeis

有効なもの:

<expControl:MainControls DataContext="{Binding RelativeSource={RelativeSource Self}}"
                         ProtocolNumber="{Binding Path=Number, Mode=TwoWay}"/>

=>実行notDataContext宣言でUserControlを設定し、代わりにRelativeSourceまたはElementNameバインディングを使用します。

6
H.B.

バインディングのRelativeSourceを指定していない場合は、コンストラクターでDataContextを設定してみてください。

    public Window1()
    {
        Number= 15;
        DataContext = this;
        InitializeComponent();
    }
2
Mizipzor