10

私の質問は基本的にこれです。ただし、問題を簡単に再現できるように、さらに情報とコードを提供すると役立つと思いました。

RibbonControlsLibraryの Microsoft.Windows.Controls.Ribbon.RibbonComboBox を操作することは、バグでいっぱいの大きな沼地を歩いているように感じられます。

だれでも。私が遭遇した最大の問題は、SelectedItem のデータバインドでした。

以下は、私が始めたものです ( RibbonGallery を知ってから? )。ComboBox のサブ要素に ItemsSource と SelectedItem があり、同じレベルでさえないことで、私はすでにヒービージービーを手に入れましたが、それは正しいようです。

サンプル アプリでは、ViewModel のコンストラクターで SelectedItem を設定しています。ただし、アプリを実行すると、SelectedItem は表示されません。VSデザイナーでさえ、「2番目のオプション」を正しく表示しています!

実行中のアプリ: 実行中のアプリVS デザイナー:ビジュアル スタジオ デザイナー

SelectedItem セッターをデバッグすると、複数のパスがあることがわかります。ctor(1、以下のデバッグログを参照)で初めて「2番目のオプション」に設定した後、null (2)にリセットされます(外部コードによって、コントロール自体で計算されます)。UI でドロップダウンを開くと、再度 null に設定され (3)、値を選択すると、この値に 2 回設定されます (4,5)。「2 番目のオプション」を選択してから、「1 番目のオプション」で手順を繰り返しました (6-9)。これにより、次のログが生成されました (リボン コントロールからの 1,000 と 1 つのバインディング例外を無視しています...):

ここに画像の説明を入力

大きな問題は明らかに (2) で、最初の選択がリセットされます。コントロールが最初に表示されたときにリセットされるように見えます。非常に厄介な回避策は、タイマーで値を設定することです。ユーザー コントロールの Loaded イベントで設定すると、このサンプル アプリではうまくいきますが、より重い実際のアプリではうまくいきません。とにかく、それはすべて間違っているように感じます。誰もがより良い解決策を知っていますか?

Xaml:

<UserControl x:Class="WpfApplication1.RibbonComboBoxDemo"
             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" 
             xmlns:r="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon" 
             xmlns:local="clr-namespace:WpfApplication1"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">

    <UserControl.DataContext>
        <local:ViewModel />
    </UserControl.DataContext>

    <Grid>
        <r:Ribbon >
            <r:RibbonTab Header="First Tab">
                <r:RibbonGroup Header="Group">
                    <r:RibbonComboBox >
                        <r:RibbonGallery SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
                            <r:RibbonGalleryCategory ItemsSource="{Binding Controls}" DisplayMemberPath="Caption" />
                        </r:RibbonGallery>
                    </r:RibbonComboBox>
                </r:RibbonGroup>
            </r:RibbonTab>
            <r:RibbonTab Header="Second Tab" />
        </r:Ribbon>
    </Grid>
</UserControl>

ビューモデル:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;

namespace WpfApplication1
{
    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public ObservableCollection<ControlBaseModel> Controls { get; private set; }


        private ControlBaseModel _selectedItem;
        public ControlBaseModel SelectedItem { get { return _selectedItem; } set { LogSelectedItemChange(value); _selectedItem = value; OnPropertyChanged("SelectedItem"); } }

        public ViewModel()
        {
            this.Controls = new ObservableCollection<ControlBaseModel>();

            this.Controls.Add(new ControlBaseModel() { Caption = "first option" });
            this.Controls.Add(new ControlBaseModel() { Caption = "second option" });

            this.SelectedItem = this.Controls[1]; // set to second option
        }

        int i = 0;
        private void LogSelectedItemChange(ControlBaseModel value)
        {
            i++;
            string setObject = "null";
            if (value != null)
            {
                setObject = value.Caption;
            }
            Debug.WriteLine(string.Format("{0}: SelectedItem.set(): {1}", i, setObject));
        }

    }

    public class ControlBaseModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        private string _name;
        public string Name { get { return _name; } set { _name = value; OnPropertyChanged("Name"); } }

        private string _caption;
        public string Caption { get { return _caption; } set { _caption = value; OnPropertyChanged("Caption"); } }
    }
}
4

2 に答える 2

5

アプリケーションで ComboBox SelectedItem が null にリセットされる前に View/UserControl ロード イベントが発生していますが、ComboBox ロード イベントは実際には 2 回発生し、2 回目は十分に「遅く」発生します。したがって、より良いものを喜んで捨てる私の現在の解決策は次のとおりです。

<r:RibbonComboBox>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction Command="{Binding LoadedCommand}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <r:RibbonGallery SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
        <r:RibbonGalleryCategory ItemsSource="{Binding Controls}" DisplayMemberPath="Caption"/>
    </r:RibbonGallery>
</r:RibbonComboBox>

ビューモデル:

private ControlBaseModel _lastNonNullSelectedItem;

public ObservableCollection<ControlBaseModel> Controls { get; private set; }

private ControlBaseModel _selectedItem;
public ControlBaseModel SelectedItem 
{ 
    get { return _selectedItem; } 
    set 
    { 
        if (value != null) { _lastNonNullSelectedItem = value; } 
        _selectedItem = value; 
        OnPropertyChanged("SelectedItem"); 
    } 
}
public ICommand LoadedCommand { get; private set; }


public ViewModel()
{
    this.Controls = new ObservableCollection<ControlBaseModel>();
    this.LoadedCommand = new ActionCommand(OnLoaded); // ActionCommand: simple implementation of ICommand

    this.Controls.Add(new ControlBaseModel() { Caption = "first option" });
    this.Controls.Add(new ControlBaseModel() { Caption = "second option" });

    this.SelectedItem = this.Controls[1]; // set to second option
}

private void OnLoaded()
{
    this.SelectedItem = _lastNonNullSelectedItem;
}
于 2013-03-22T10:14:36.473 に答える
3

標準の ComboBox を使用するだけになりました。

<ComboBox SelectedItem="{Binding Item}" ItemsSource="{Binding Items}"/>

RibbonComboBox と同じ (非常に似た) スタイルが必要な場合は、

<ComboBox SelectedItem="{Binding Item}" ItemsSource="{Binding Items}" IsEditable="True" IsReadOnly="True"/>
于 2013-05-22T15:03:16.950 に答える