WPF:绑定到(可观察的)词典

时间:2011-05-17 11:27:07

标签: wpf binding dictionary indexing observable

我在我的项目中使用此ObservableCollection-Class:Link
我想将RibbonMenuButton绑定到ObservableDictionary<string,bool>

<r:RibbonMenuButton ItemsSource="{Binding MyDictionary}">
    <r:RibbonMenuButton.ItemContainerStyle>
        <Style TargetType="{x:Type r:RibbonMenuItem}">
            <Setter Property="IsCheckable" Value="true"/>
            <Setter Property="Header" Value="{Binding Path=Key}"/>
            <Setter Property="IsChecked" Value="{Binding Path=Value}"/>
        </style>
    </r:RibbonMenuButton.ItemContainerStyle>
</r:RibbonMenuButton>

但是我得到了异常,因为内部IDictionary-KeyValuePairs的Value-Properties是只读的。任何想法如何解决这个问题?
我想到了类似的东西:

<Setter Property="IsChecked" Value="{Binding Source=MyDictionary[{Binding Path=Key}]}"/>

但这不会起作用{Binding} {绑定}的原因......

4 个答案:

答案 0 :(得分:3)

这不起作用,因为您的字典不被视为字典而是IEnumerable<KeyValuePair<string, bool>>。因此,每个RibbonMenuItem都绑定到KeyValuePair<string, bool>,其中包含只读属性KeyValue
你可以做两个一件事 s

1.使用ObservableCollection<Tuple<string, bool>>代替字典并将IsChecked绑定到Item2
  2.创建一个包含IsChecked属性的小助手类,并更改字典以包含该类作为值,并将IsChecked绑定到Value.IsChecked

我会回答二,因为所需的变化和可能的副作用较小 我的回答是假设您希望在IsChecked上进行双向绑定。如果没有,请使用slugster的答案。

答案 1 :(得分:1)

默认情况下,WPF绑定是双向的。单向进行,看看是否能解决您的问题。

<r:RibbonMenuButton ItemsSource="{Binding MyDictionary}">
    <r:RibbonMenuButton.ItemContainerStyle>
        <Style TargetType="{x:Type r:RibbonMenuItem}">
            <Setter Property="IsCheckable" Value="true"/>
            <Setter Property="Header" Value="{Binding Key, Mode=OneWay}"/>
            <Setter Property="IsChecked" Value="{Binding Value, Mode=OneWay}"/>
        </style>
    </r:RibbonMenuButton.ItemContainerStyle>
</r:RibbonMenuButton>

以下是您的参考:MSDN Windows Presentation Foundation Data Binding: Part 1(具体检查靠近页面底部的绑定模式部分)

答案 2 :(得分:1)

如果您想在不使用帮助程序类的情况下将MenuItems绑定到Dictionary<string, bool>,就像接受的答案所示,这里是 minimal-change 解决方案(无需添加其他任何事情):

  • Click内定义ItemContainerStyle事件,ClickEventHandler将更新dicitonary。
  • 声明一个字典并在UserControl的/ Window的构造函数
  • 中初始化它

在代码中:

MainWindow.xaml:

<MenuItem Header="_My settings" ItemsSource="{Binding MySettings}">
    <MenuItem.ItemContainerStyle>
      <Style TargetType="{x:Type MenuItem}">
        <Setter Property="IsCheckable" Value="true"/>
        <Setter Property="Header" Value="{Binding Key, Mode=OneWay}"/>
        <Setter Property="IsChecked" Value="{Binding Value, Mode=OneWay}"/>
        <!-- this is the main line of code -->
        <EventSetter Event="Click" Handler="MySettings_ItemClick"/>
      </Style>
    </MenuItem.ItemContainerStyle>
</MenuItem>

MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    // properties...

    // Declaration of the dictionary
    public Dictionary<string, bool> MySettings{ get; set; }

    public MainWindow()
    {
        InitializeComponent();
        // Initialize the dictionary
        MySettings = new Dictionary<string, bool>()
        {
            { "SettingOne", true}
            // Other pairs..
        };
    }
    // other things..

    // ClickEvent hanlder
    private void MySettings_ItemClick(object sender, RoutedEventArgs e)
    {
        MenuItem clickedItem = (sender as MenuItem);
        MySettings[clickedItem.Header as string] = clickedItem.IsChecked;
    }
} // end of MainWindow class

就是这样!你们都准备好了!

对于OneWay绑定的XAML代码,slugster and his answer的积分:)

答案 3 :(得分:0)

作为绑定到字典的这个问题的一般解决方案,我创建了一个UpdateableKeyValuePair并返回通常的KeyValuePair的instaed。这是我的班级:

   public class UpdateableKeyValuePair<TKey,TValue>
      {
      private IDictionary<TKey, TValue> _owner;
      private TKey _key;
      public UpdateableKeyValuePair(IDictionary<TKey, TValue> Owner, TKey Key_)
         {
         _owner = Owner;
         _key = Key_;
         }

      public TKey Key
         {
         get
            {
            return _key;
            }
         }

      public TValue Value
        {
        get
          {
          return _owner[_key];
          }
       set
         {
          _owner[_key] = value;
         }
      }
    }