1

オブジェクトへの標準のWPFデータバインディングを使用して、テキストボックスを備えたWPFウィンドウがあります。これはすべて正常に機能します。問題は次のとおりです。

ユーザーが時間の見積もりを入力しています。ユーザーにデータを時間または分で入力するオプションを提供したいと思います(ドロップダウンリストから)。データを数分で保持したいのですが、ユーザーが時間を選択した場合は、入力に60を掛けてデータを保存します。

WPFデータバインディングを使用してこれを実現するにはどうすればよいですか?これも可能ですか?

編集

たとえば、ドロップダウンリストが時間に設定されている場合は90分が1.5として表示されますが、miutesが選択されている場合は90分が表示されます。

4

5 に答える 5

3

最初に質問を完全に誤解した後、これが私の最初の賞金を獲得するための私の努力です;)

<Window.Resources>        
    <local:DivisionConverter x:Key="HoursConverter" Divisor="60"/>

    <DataTemplate DataType="{x:Type local:MyObject}">
        <StackPanel Orientation="Horizontal">
            <TextBox x:Name="InputBox" Text="{Binding Path=Estimate}" Width="80"/>
            <ComboBox x:Name="InputUnit" SelectedItem="Minutes">
                <System:String>Minutes</System:String>
                <System:String>Hours</System:String>
            </ComboBox>
        </StackPanel>            
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding ElementName=InputUnit, Path=SelectedItem}" Value="Hours">
                <Setter TargetName="InputBox" Property="Text" Value="{Binding Path=Estimate, Converter={StaticResource HoursConverter}}"/>
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>        
</Window.Resources>
<Grid>
    <ContentControl VerticalAlignment="Top">
        <local:MyObject Estimate="120"/>
    </ContentControl>
</Grid>

一般的に、私は特殊なコンバーターが嫌いです。しばらくすると、どのコンバーターが正確に何を実行するかがわからなくなり、必要だと思うたびにコンバーターコードを実行することになります。さらに悪いことに、まったく同じことを実行する2番目のコンバーターを作成します。だから今、私は他のすべてが失敗したときにだけそれらを使用しています。

代わりに、私は汎用のDivisionConverterを定義しました。これは、Convertメソッドの値を分割し、ConvertBackメソッドの値を、期待どおりに乗算します。ここでコードを確認する必要はありません;)

さらに、他の人がMultiBindingを使用したり、(さらに悪いことに)このUIロジックをゲッターとセッターに追加したりする場合にDataTemplateとTriggersを使用します。これにより、この比較的単純なUIロジックがすべて1つの監視可能な場所に保持されます。

完全を期すために、これはコードビハインドです。

public class MyObject
{
    public double Estimate { get; set; }
}


public class DivisionConverter : IValueConverter
{
    public double Divisor { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        double doubleValue = (double)value;
        return doubleValue / Divisor;            
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {           
        double inputValue;
        if (!double.TryParse((string)value, NumberStyles.Any, culture, out inputValue)) 
            return 0;

        return inputValue * Divisor;
    }
}
于 2009-08-17T19:54:53.903 に答える
3

ウィンドウで特別なプロパティを使用できます。

<ComboBox x:Name="Units">
    <sys:String>Hours</sys:String>
    <sys:String>Minutes</sys:String>
</ComboBox>
<TextBox x:Name="Value" Text="{Binding Path=Estimate, ElementName=ThisWindow}" />

そして、特別なプロパティを実装します:

public double Estimate
{
    get
    {
        switch(this.Units.SelectedItem as String)
        {
        case "Hours":
            return this.estimate / 60.0;
        default:
            return this.estimate;
        }
    }

    set
    {
        switch(this.Units.SelectedItem as String)
        {
        case "Hours":
            this.estimate = value * 60.0;
            break;
        default:
            this.estimate = value;
            break;
        }

        this.OnPropertyChanged("Estimate");
    }
}
于 2009-08-16T19:47:30.513 に答える
2

これを実現するには、値コンバーターを使用します ( http://blogs.msdn.com/delay/archive/2008/05/04/ivalueconverter-the-swiss-army-knife-of-bindings-propertyviewer-sample-is-a- wpf-silverlight-visualization-and-debugging-aid.aspx )

于 2009-07-01T00:40:11.263 に答える
1

MultiValueConverterを使用できます:

XAML

        <ComboBox ItemsSource="{StaticResource values}">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock>
                      <TextBlock.Text>
                        <MultiBinding Converter="{StaticResource minutToHours}">
                          <Binding/>
                          <Binding Path="IsChecked" ElementName="chkHours"/>
                        </MultiBinding>
                      </TextBlock.Text>
                    </TextBlock>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
        <CheckBox Name="chkHours" Content="Show hours"/>

ConverterのC#コード

public class MinuteToHoursConverter : IMultiValueConverter
{
    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        int minutes = 0;
        if (values[0] is TimeSpan)
        {
            minutes = (int)((TimeSpan)values[0]).TotalMinutes;
        }
        else
        {
            minutes = System.Convert.ToInt32(values[0]);
        }
        bool showHours = System.Convert.ToBoolean(values[1]);
        if (showHours)
            return (minutes / 60.0).ToString();
        else
            return minutes.ToString();
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }

    #endregion
}

しかし、このソリューションはおそらく最適ではありません... MVVMパターンを使用している場合の最善の方法は、ViewModelに追加のプロパティを作成して、正しい値を計算することです。

于 2009-08-16T19:57:38.880 に答える
0

考えすぎかもしれませんが、コンボボックスには表示値と実際の値 (ユーザーの舞台裏) の両方があるため、見積もりリストに 2 つの列を持たないのはなぜですか...それぞれ時間と分の両方です。 . 次に、チェックされているモードに基づいて、「表示」バインディングをそれぞれのモードに変更します。このようにして、必要な舞台裏の分数が常に保存されます。他の変換はありません。

于 2009-08-19T18:32:54.643 に答える