绑定到项目控件中的选定项

时间:2021-08-11 18:59:38

I created a custom ComboBox as follows: (note, code is not correct but you should get the general idea.) The ComboBox contains 2 dependency properties which matter: TitleText and DescriptionText.

我创建了一个自定义组合框,如下所示:(注意,代码不正确,但您应该理解它的大意)。ComboBox包含两个依赖属性:TitleText和DescriptionText。

<Grid>
  <TextBlock x:Name="Title"/>
  <Grid x:Name="CBG">
    <ToggleButton/>
    <ContentPresenter/>
    <Popup/>
  </Grid>
</Grid>

I want to use this ComboBox to display a wide range of options. I created a class called Setting which inherits from DependencyObject to create usable items, I created a DataTemplate to bind the contents of this Settings object to my ComboBox and created a UserControl which contains an ItemsControl which has as a template my previously mentioned DataTemplate. I can fill it with Setting objects.

我想用这个ComboBox来显示各种各样的选项。我创建了一个名为设置的类,它从依赖对象继承来创建可用的项目,我创建了一个DataTemplate来将这个设置对象的内容绑定到我的ComboBox,并创建了一个UserControl,其中包含一个ItemsControl,它是我之前提到的DataTemplate的模板。我可以用设置对象来填充它。

<DataTemplate x:Key="myDataTemplate">
  <ComboBox TitleText="{Binding Title}" DescriptionText="{Binding DescriptionText}"/>
</DataTemplate>

<UserControl>
  <Grid>
    <StackPanel Grid.Column="0">
      <ItemsControl Template="{StaticResource myDataTemplate}">
        <Item>
          <Setting Title="Foo" Description="Bar">
            <Option>Yes</Option><Option>No</Option>
          </Setting>
        </Item>
      </ItemsControl>
    </StackPanel>
    <StackPanel Grid.Column="1">
      <TextBlock x:Name="Description"/>
    </StackPanel>
  </Grid>
</UserControl>

I would like to have the DescriptionText of the selected ComboBox (selected by either the IsFocus of the ComboBox control or the IsOpen property of the popup) to be placed in the Description TextBlock in my UserControl.

我希望选择ComboBox的Description文本(由ComboBox控件的IsFocus或弹出窗口的IsOpen属性选择)放在UserControl的Description TextBlock中。

One way I managed to achieve this was replacing my ItemsControl by a ListBox but this caused several issues: it always showed a scrollbar even though I disabled it, it wouldn't catch focus when my popup was open but only when I explicitly selected the item in my ListBox, when I enabled the OverridesDefaultStyle property the contents of the ListBox wouldn't show up at all, I had to re-theme the ListBox control to match my UserControl layout...

我设法实现这一点的方法之一是代替我的ItemsControl列表框,但这引起了几个问题:它总是显示滚动条,即使我禁用它,它不会抓重点当我弹出开放,但只有当我明确选择项列表框,当我启用OverridesDefaultStyle属性列表框的内容不会出现在所有,我不得不re-theme ListBox控件匹配我的用户控件布局…

What's the best and easiest way to get my DescriptionText to show up without using a ListBox or creating a custom Selector control (as that had the same effect as a ListBox)?

在不使用列表框或创建自定义选择器控件(因为它具有与列表框相同的效果)的情况下,让description文本显示出来的最佳和最简单的方法是什么?

The goal at the end is to loop through all the items (maybe get them into an ObservableCollection or some sort and to save them into my settings file.

最后的目标是遍历所有的条目(可能会将它们放入一个ObservableCollection或某种类型,并将它们保存到我的设置文件中。

2 个解决方案

#1


1  

I think I know what you are trying to do. Here is a possible solution.

我想我知道你想做什么。这里有一个可能的解决方案。

You should use a ListBox (or anything deriving from Selector control) in order to use the SelectedItem property.

为了使用SelectedItem属性,您应该使用列表框(或任何从选择器控件派生的内容)。

<UserControl>
  <Grid>
    <StackPanel Grid.Column="0">
      <ListBox x:Name="SettingListBox" Template="{StaticResource myDataTemplate}">
        <Item>
          <Setting Title="Foo" Description="Bar">
            <Option>Yes</Option><Option>No</Option>
          </Setting>
        </Item>
      </ListBox >
    </StackPanel>
    <StackPanel Grid.Column="1">
      <TextBlock x:Name="Description"
          Text="{Binding SelectedItem.Description, ElementName=SettingListBox}"/>
    </StackPanel>
  </Grid>
</UserControl>

To solve the problem where your ListBox does not focus on the item when you open the ComboBox drop-down menu, I have an attached property that will fix that for you.

要解决列表框在打开ComboBox下拉菜单时不关注项目的问题,我有一个附加属性,它将为您修复该属性。

public class ListBoxHelper
{
    #region Dependency Property

    public static bool GetCanFocusParent(DependencyObject obj)
    {
        return (bool)obj.GetValue(CanFocusParentProperty);
    }

    public static void SetCanFocusParent(DependencyObject obj, bool value)
    {
        obj.SetValue(CanFocusParentProperty, value);
    }

    // Using a DependencyProperty as the backing store for CanFocusParent.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CanFocusParentProperty =
        DependencyProperty.RegisterAttached("CanFocusParent", typeof(bool), typeof(ListBoxHelper), new UIPropertyMetadata(false, OnCanFocusParentChanged));



    #endregion

    private static void OnCanFocusParentChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var element = obj as UIElement;
        if(element == null) return;

        if((bool)args.NewValue)
            element.PreviewMouseDown += FocusOnParent;
        else
            element.PreviewMouseDown -= FocusOnParent;
    }

    private static void FocusOnParent(object sender, RoutedEventArgs e)
    {
        var listBoxItem = VisualUpwardSearch<ListBoxItem>(sender as DependencyObject) as ListBoxItem;
        if (listBoxItem != null) listBoxItem.IsSelected = true;
    }

    public static DependencyObject VisualUpwardSearch<T>(DependencyObject source)
    {
        while (source != null && source.GetType() != typeof(T))
            source = VisualTreeHelper.GetParent(source);

        return source;
    }
}

What this little class does is help your control to focus on the ListBox selected item when you activate a control inside it (ie. your ComboBox). It works when the Mouse is clicked inside the ListBox item.

这个小类所做的是帮助您的控件在激活内部控制时将焦点集中在列表框中。你的组合框)。当单击列表框项中的鼠标时,它将工作。

Now all you have to do is attach it to your ComboBox like so:

现在你要做的就是把它贴在你的盒子上,就像这样:

<DataTemplate x:Key="myDataTemplate">
  <ComboBox
      TitleText="{Binding Title}"
      DescriptionText="{Binding DescriptionText}"
      CotrolHelper:ListBoxHelper.CanFocusParent="true"/>
</DataTemplate>

Where ControlHelper is:

ControlHelper在哪里:

xmlns:ControlHelper="clr-namespace:WhereYouPutYour.ListBoxHelperClass"

And finally, to Disable (but I recommend setting to Auto) the Scrollbar, you can use the ScrollViewer attached property in your ListBox like this:

最后,禁用(但我建议设置为Auto)滚动条,您可以使用ScrollViewer在您的列表框中附加的属性如下:

<ListBox
    x:Name="SettingListBox"
    Template="{StaticResource myDataTemplate}"
    ScrollViewer.VerticalScrollBarVisibility="Disabled" >
    <Item>
        <Setting Title="Foo" Description="Bar">
            <Option>Yes</Option><Option>No</Option>
        </Setting>
    </Item>
</ListBox >

#2


0  

You can use a ListBox, just change how the data is presented. For example, this code will default to not having a scroll bar. (I want scroll bars, so I have to explicitly wrap the whole thing in a ScrollViewer.)

您可以使用一个列表框,只需要更改数据的呈现方式。例如,该代码默认没有滚动条。(我想要滚动条,所以我必须显式地将整个内容包装在ScrollViewer中。)

                <ListBox.Template>
                    <ControlTemplate>
                        <StackPanel IsItemsHost="True" >
                        </StackPanel>
                    </ControlTemplate>
                </ListBox.Template>

#1


1  

I think I know what you are trying to do. Here is a possible solution.

我想我知道你想做什么。这里有一个可能的解决方案。

You should use a ListBox (or anything deriving from Selector control) in order to use the SelectedItem property.

为了使用SelectedItem属性,您应该使用列表框(或任何从选择器控件派生的内容)。

<UserControl>
  <Grid>
    <StackPanel Grid.Column="0">
      <ListBox x:Name="SettingListBox" Template="{StaticResource myDataTemplate}">
        <Item>
          <Setting Title="Foo" Description="Bar">
            <Option>Yes</Option><Option>No</Option>
          </Setting>
        </Item>
      </ListBox >
    </StackPanel>
    <StackPanel Grid.Column="1">
      <TextBlock x:Name="Description"
          Text="{Binding SelectedItem.Description, ElementName=SettingListBox}"/>
    </StackPanel>
  </Grid>
</UserControl>

To solve the problem where your ListBox does not focus on the item when you open the ComboBox drop-down menu, I have an attached property that will fix that for you.

要解决列表框在打开ComboBox下拉菜单时不关注项目的问题,我有一个附加属性,它将为您修复该属性。

public class ListBoxHelper
{
    #region Dependency Property

    public static bool GetCanFocusParent(DependencyObject obj)
    {
        return (bool)obj.GetValue(CanFocusParentProperty);
    }

    public static void SetCanFocusParent(DependencyObject obj, bool value)
    {
        obj.SetValue(CanFocusParentProperty, value);
    }

    // Using a DependencyProperty as the backing store for CanFocusParent.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CanFocusParentProperty =
        DependencyProperty.RegisterAttached("CanFocusParent", typeof(bool), typeof(ListBoxHelper), new UIPropertyMetadata(false, OnCanFocusParentChanged));



    #endregion

    private static void OnCanFocusParentChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var element = obj as UIElement;
        if(element == null) return;

        if((bool)args.NewValue)
            element.PreviewMouseDown += FocusOnParent;
        else
            element.PreviewMouseDown -= FocusOnParent;
    }

    private static void FocusOnParent(object sender, RoutedEventArgs e)
    {
        var listBoxItem = VisualUpwardSearch<ListBoxItem>(sender as DependencyObject) as ListBoxItem;
        if (listBoxItem != null) listBoxItem.IsSelected = true;
    }

    public static DependencyObject VisualUpwardSearch<T>(DependencyObject source)
    {
        while (source != null && source.GetType() != typeof(T))
            source = VisualTreeHelper.GetParent(source);

        return source;
    }
}

What this little class does is help your control to focus on the ListBox selected item when you activate a control inside it (ie. your ComboBox). It works when the Mouse is clicked inside the ListBox item.

这个小类所做的是帮助您的控件在激活内部控制时将焦点集中在列表框中。你的组合框)。当单击列表框项中的鼠标时,它将工作。

Now all you have to do is attach it to your ComboBox like so:

现在你要做的就是把它贴在你的盒子上,就像这样:

<DataTemplate x:Key="myDataTemplate">
  <ComboBox
      TitleText="{Binding Title}"
      DescriptionText="{Binding DescriptionText}"
      CotrolHelper:ListBoxHelper.CanFocusParent="true"/>
</DataTemplate>

Where ControlHelper is:

ControlHelper在哪里:

xmlns:ControlHelper="clr-namespace:WhereYouPutYour.ListBoxHelperClass"

And finally, to Disable (but I recommend setting to Auto) the Scrollbar, you can use the ScrollViewer attached property in your ListBox like this:

最后,禁用(但我建议设置为Auto)滚动条,您可以使用ScrollViewer在您的列表框中附加的属性如下:

<ListBox
    x:Name="SettingListBox"
    Template="{StaticResource myDataTemplate}"
    ScrollViewer.VerticalScrollBarVisibility="Disabled" >
    <Item>
        <Setting Title="Foo" Description="Bar">
            <Option>Yes</Option><Option>No</Option>
        </Setting>
    </Item>
</ListBox >

#2


0  

You can use a ListBox, just change how the data is presented. For example, this code will default to not having a scroll bar. (I want scroll bars, so I have to explicitly wrap the whole thing in a ScrollViewer.)

您可以使用一个列表框,只需要更改数据的呈现方式。例如,该代码默认没有滚动条。(我想要滚动条,所以我必须显式地将整个内容包装在ScrollViewer中。)

                <ListBox.Template>
                    <ControlTemplate>
                        <StackPanel IsItemsHost="True" >
                        </StackPanel>
                    </ControlTemplate>
                </ListBox.Template>