RibbonGallery.SelectedValue не обновляет SelectedItem - PullRequest
0 голосов
/ 30 октября 2019

Я использую ленточную библиотеку Microsoft: System.Windows.Controls.Ribbon. Я знаю, что этот вопрос выглядит большим, но то, что я пытаюсь сделать, на самом деле не так уж сложно, в нем участвуют всего несколько частей.

Цель

Я пытаюсь связатьвыбор RibbonComboBox для свойства одного из моих классов, который я назову TestBindingSource, но мне нужно иметь возможность отменить изменение выбора. Поэтому, если они выбирают элемент из RibbonComboBox, но затем отменяют это изменение, выбор должен оставаться таким, как был.

Элементы, отображаемые в RibbonComboBox, представляют членов Enum,который я назову TestEnum. Я создал еще один класс TestEnumGalleryItem для представления значений TestEnum в RibbonComboBox, и я использую RibbonGallery.SelectedValue и RibbonGallery.SelectedValuePath для привязки к свойству в TestBindingSource. В случае, если за этим было слишком трудно следить, вы сможете понять, что я имею в виду из моего кода.

Код

Ниже приведена упрощенная версия моего реального кода, постарайтесь неПрикрепите мне слишком много очков для стиля. Я проверил это в новом проекте, и его можно использовать, чтобы показать проблему, с которой я столкнулся. Не забудьте добавить ссылку на ленточную библиотеку Microsoft.

MainWindow.xaml

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:VBTest"
        mc:Ignorable="d"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Ribbon>
            <RibbonTab Header="Test">
                <RibbonGroup>
                    <RibbonComboBox Name="TestComboBox">
                        <RibbonGallery Name="TestGallery" MaxColumnCount="1" ScrollViewer.VerticalScrollBarVisibility="Auto" SelectedValuePath="EnumValue" SelectedValue="{Binding BindingSource.TestEnumValue}">
                            <RibbonGallery.ItemsSource>
                                <x:Array Type="local:TestEnumGalleryCategory">
                                    <local:TestEnumGalleryCategory/>
                                </x:Array>
                            </RibbonGallery.ItemsSource>
                            <RibbonGallery.CategoryTemplate>
                                <HierarchicalDataTemplate ItemsSource="{Binding Items}">
                                    <HierarchicalDataTemplate.ItemTemplate>
                                        <DataTemplate>
                                            <RibbonGalleryItem ToolTipTitle="{Binding EnumName}" ToolTipDescription="{Binding EnumDescription}">
                                                <TextBlock Text="{Binding EnumName}" Margin="0, -3, -0, -3"/>
                                            </RibbonGalleryItem>
                                        </DataTemplate>
                                    </HierarchicalDataTemplate.ItemTemplate>
                                </HierarchicalDataTemplate>
                            </RibbonGallery.CategoryTemplate>
                        </RibbonGallery>
                    </RibbonComboBox>

                    <RibbonButton Label="Break" Click="RibbonButton_Click"/>
                </RibbonGroup>                
            </RibbonTab>
        </Ribbon>
    </Grid>
</Window>

MainWindow.xaml.vb

Imports System.ComponentModel

Class MainWindow
    Public Sub New()
        BindingSource = New TestBindingSource
        InitializeComponent()
    End Sub

    Public Property BindingSource As TestBindingSource
        Get
            Return GetValue(BindingSourceProperty)
        End Get
        Set(ByVal value As TestBindingSource)
            SetValue(BindingSourceProperty, value)
        End Set
    End Property
    Public Shared ReadOnly BindingSourceProperty As DependencyProperty =
                           DependencyProperty.Register("BindingSource",
                           GetType(TestBindingSource), GetType(MainWindow))

    Private Sub RibbonButton_Click(sender As Object, e As RoutedEventArgs)
        Stop
    End Sub
End Class

Public Enum TestEnum
    ValueA
    ValueB
End Enum

Public Class TestEnumGalleryCategory
    Public Property Items As New List(Of TestEnumGalleryItem) From {New TestEnumGalleryItem With {.EnumValue = TestEnum.ValueA, .EnumName = "Value A", .EnumDescription = "A's description"},
                                                                    New TestEnumGalleryItem With {.EnumValue = TestEnum.ValueB, .EnumName = "Value B", .EnumDescription = "B's description"}}
End Class

Public Class TestEnumGalleryItem
    Public Property EnumValue As TestEnum = TestEnum.ValueA

    Public Property EnumName As String

    Public Property EnumDescription As String
End Class

Public Class TestBindingSource
    Implements INotifyPropertyChanged

    Private _TestEnumValue As TestEnum = TestEnum.ValueA
    Property TestEnumValue As TestEnum
        Get
            Return _TestEnumValue
        End Get
        Set(value As TestEnum)
            'Don't actually set new value, just leave it the same to simulate cancelation
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(TestEnumValue)))
        End Set
    End Property

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
End Class

Проблема

Когда вы запустите код, вы увидите, что RibbonComboBox по умолчанию отображает «Значение A». Измените выбор на «Значение B». Выбор RibbonComboBox изменяется и теперь отображает «Значение B». Это не то, чего я хочу, выбор должен немедленно измениться на «Значение А.».

Если вы посмотрите на код для TestBindingSource.TestEnumValue, вы увидите, что я на самом деле не сохраняюпри установке нового значения, вместо этого я оставляю старое для имитации отмены изменения пользователем. Затем я вызываю событие PropertyChanged, чтобы обновить пользовательский интерфейс, чтобы он знал реальное значение свойства.

После того, как вы изменили значение «Значение B», нажмите кнопку «Разрыв» (включена дляудобство). В окне просмотра Visual Studio сравните значения TestGallery.SelectedItem и TestGallery.SelectedValue. Вы увидите, что TestGallery.SelectedValue содержит правильное TestEnum значение ValueA. Теперь посмотрите на TestGallery.SelectedItem, и вы увидите, что он по-прежнему содержит элемент, представляющий ValueB.

Так что, хотя RibbonGallery был должным образом проинформирован, что значение теперь должно быть ValueA, этовсе еще показывает ValueB. Как я могу это исправить?

Я буду на одном уровне с вами, у меня нет тонны времени, чтобы тратить на эту ошибку, и я привык делать хакерские обходные пути, когда дело доходит доленты. Будем благодарны за любое решение, которое вы можете дать мне, как правильно настроить RibbonGallery (и, следовательно, RibbonComboBox).

1 Ответ

0 голосов
/ 31 октября 2019

После дополнительных испытаний и исследований я понял, что эта проблема не уникальна для библиотеки ленточных носителей. На самом деле, это похоже на проблему с нормальным ComboBox тоже и предположительно со всеми ItemsControls. Как только я понял это, я смог более эффективно искать ответ и нашел решение здесь:
https://nathan.alner.net/2010/04/25/cancelling-selection-change-in-a-bound-wpf-combo-box/

Это не совсем чистое решение, но в моем конкретном случае установка значения наНовый выбор, а затем немедленная его установка не вызывают никаких проблем, поэтому я так и сделал. Для записи: при установке выбора я использовал DispatcherPriority.DataBind вместо DispatcherPriority.ContextIdle, таким образом, изменение даже не отображается в пользовательском интерфейсе, но решение все еще работает.

...