3

次のようないくつかの ToggleButton/RadioButton 要素を提示したいと思います。

  1. 列挙型にマップします。つまり、DataContext には「public Mode CurrentMode」プロパティがあります。
  2. 相互に排他的 (1 つのボタンのみがチェックされている)
  3. ボタンをクリックしても、状態はすぐには変わりません。代わりに、リクエストがサーバーに送信されます。応答が到着すると、状態が変化します。
  4. チェックされている/チェックされていない状態の異なるイメージを持つ

たとえば、4 つのボタンは次のビューモデルを表示します。

public class ViewModel
{
    public enum Mode { Idle, Active, Disabled, Running }
    Mode m_currentMode = Mode.Idle;

    public Mode CurrentMode
    {
        get { return m_currentMode; }
        set
        {
            SendRequest(value);
        }
    }

    // Called externally after SendRequest, not from UI
    public void ModeChanged(Mode mode)
    {
        m_currentMode = mode;
        NotifyPropertyChanged("CurrentMode");
    }
}

私の最初のアプローチは、How to bind RadioButtons to an enum?のソリューションを使用することでした。、しかし、セッターで NotifyPropertyChanged を呼び出さなくても、ボタンの状態がすぐに変わるため、それだけでは不十分です。さらに、「GroupName」ハックは好きではありません。

何か案は?複数のビューにこのようなボタンがたくさん必要なので、カスタム ボタン クラスを作成してもかまいません。

.NET 3.5 SP1 と VS2008 を使用しています。

4

1 に答える 1

0

RadioButton を使用する場合は、RadioButton のデフォルトの動作を回避するためにいくつかの微調整を行うだけで済みます。

回避する必要がある最初の問題は、共通の直接の親コンテナーに基づく RadioButton の自動グループ化です。「GroupName」ハックが気に入らないので、他のオプションは、各 RadioButton を独自のグリッドまたは他のコンテナー内に配置することです。これにより、各ボタンが独自のグループのメンバーになり、IsChecked バインディングに基づいて動作するようになります。

    <StackPanel Orientation="Horizontal">
        <Grid>
            <RadioButton IsChecked="{Binding Path=CurrentMode, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Idle}">Idle</RadioButton>
        </Grid>
        <Grid>
            <RadioButton IsChecked="{Binding Path=CurrentMode, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Active}">Active</RadioButton>
        </Grid>
        <Grid>
            <RadioButton IsChecked="{Binding Path=CurrentMode, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Disabled}">Disabled</RadioButton>
        </Grid>
        <Grid>
            <RadioButton IsChecked="{Binding Path=CurrentMode, Converter={StaticResource enumBooleanConverter}, ConverterParameter=Running}">Running</RadioButton>
        </Grid>
    </StackPanel>

これは、 IsChecked プロパティにバインドしているため、 set 呼び出しをトリガーするために必要だったボタンをクリックした後、クリックされたボタンが Checked 状態にとどまらないようにする次の回避策につながります。追加の NotifyPropertyChanged を送信する必要がありますが、それを Dispatch スレッドのキューにプッシュして、ボタンが通知を受け取り、視覚的な IsChecked バインディングを更新できるようにする必要があります。これを ViewModel クラスに追加します。これはおそらく既存の NotifyPropertyChanged 実装を置き換えるものであり、クラスが質問のコードにない INotifyPropertyChanged を実装していると想定しています。

    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            Dispatcher uiDispatcher = Application.Current != null ? Application.Current.Dispatcher : null;
            if (uiDispatcher != null)
            {
                uiDispatcher.BeginInvoke(DispatcherPriority.DataBind,
                    (ThreadStart)delegate()
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                    });
            }
        }
    }

次に、CurrentMode のセッターで NotifyPropertyChanged("CurrentMode") を呼び出します。サーバーの ModeChanged 呼び出しはおそらく Dispatcher スレッドではないスレッドで行われるため、おそらくすでにこのようなものが必要でした。

最後に、異なる Checked/Unchecked の外観を持たせたい場合は、RadioButton に Style を適用する必要があります。WPF RadioButton ControlTemplate を Google ですばやく検索すると、最終的にhttp://madprops.org/blog/wpf-killed-the-radiobutton-star/というサイトが見つかりました。

于 2011-06-16T14:47:47.483 に答える