7

「FirstName」と「LastName」の2つのプロパティを持つクラスEmployeeViewModelがあります。クラスには、プロパティの変更を含むディクショナリもあります。(クラスは INotifyPropertyChanged と IDataErrorInfo を実装しており、すべて問題ありません。

私の見解では、テキストボックスがあります:

<TextBox x:Name="firstNameTextBox" Text="{Binding Path=FirstName}" />

元の値が変更された場合、テキストボックスの背景色を変更するにはどうすればよいですか? 背景色を設定するトリガーを作成することを考えましたが、何にバインドすればよいですか? コントロールが変更されたかどうかに関係なく、状態を保持するすべてのコントロールに追加のプロパティを作成したくありません。

どうも

4

6 に答える 6

12

同じプロパティでMultiBindingを2回使用するだけですが、バインディングの1つにMode=OneTimeがあります。このような:

Public Class MVCBackground
    Implements IMultiValueConverter

    Public Function Convert(ByVal values() As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IMultiValueConverter.Convert
        Static unchanged As Brush = Brushes.Blue
        Static changed As Brush = Brushes.Red

        If values.Count = 2 Then
            If values(0).Equals(values(1)) Then
                Return unchanged
            Else
                Return changed
            End If
        Else
            Return unchanged
        End If
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetTypes() As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object() Implements System.Windows.Data.IMultiValueConverter.ConvertBack
        Throw New NotImplementedException()
    End Function
End Class

そしてxamlで:

<TextBox Text="{Binding TestText}">
    <TextBox.Background>
        <MultiBinding Converter="{StaticResource BackgroundConverter}">
            <Binding Path="TestText"    />
            <Binding Path="TestText" Mode="OneTime" />
        </MultiBinding>
    </TextBox.Background>
</TextBox>

追加のプロパティやロジックは必要ありません。おそらく、すべてを独自のマークアップ拡張機能にラップすることができます。お役に立てば幸いです。

于 2009-08-13T00:51:40.477 に答える
4

値コンバーター(文字列入力をカラー出力に変換する)を使用する必要があります。最も簡単な解決策は、EmployeeViewModel に少なくとも 1 つのプロパティを追加することです。ある種のDefaultまたはOriginalValueプロパティを作成し、それと比較する必要があります。そうでなければ、「元の値」が何であったかをどのように知ることができますか? 比較する元の値を保持している何かがない限り、値が変更されたかどうかはわかりません。

したがって、テキスト プロパティにバインドし、入力文字列をビュー モデルの元の値と比較します。変更されている場合は、強調表示された背景色を返します。一致する場合は、通常の背景色を返します。FirstNameLastNameを 1 つのテキスト ボックスから比較する場合は、マルチバインディングを使用する必要があります。

これがどのように機能するかを示す例を作成しました。

<Window x:Class="TestWpfApplication.Window11"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestWpfApplication"
Title="Window11" Height="300" Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
    <local:ChangedDefaultColorConverter x:Key="changedDefaultColorConverter"/>
</Window.Resources>
<StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock>Default String:</TextBlock>
        <TextBlock Text="{Binding Path=DefaultString}" Margin="5,0"/>
    </StackPanel>
    <Border BorderThickness="3" CornerRadius="3"
            BorderBrush="{Binding ElementName=textBox, Path=Text, Converter={StaticResource changedDefaultColorConverter}}">
        <TextBox Name="textBox" Text="{Binding Path=DefaultString, Mode=OneTime}"/>
    </Border>
</StackPanel>

Window のコード ビハインドは次のとおりです。

/// <summary>
/// Interaction logic for Window11.xaml
/// </summary>
public partial class Window11 : Window
{
    public static string DefaultString
    {
        get { return "John Doe"; }
    }

    public Window11()
    {
        InitializeComponent();
    }
}

最後に、使用するコンバーターは次のとおりです。

public class ChangedDefaultColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string text = (string)value;
        return (text == Window11.DefaultString) ?
            Brushes.Transparent :
            Brushes.Yellow;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

また、TextBox の周りに境界線をラップしましたが (見た目が少し良くなったと思うため)、Background バインディングはまったく同じ方法で行うことができます。

<TextBox Name="textBox" Text="{Binding Path=DefaultString, Mode=OneTime}"
         Background="{Binding ElementName=textBox, Path=Text, Converter={StaticResource changedDefaultColorConverter}}"/>
于 2009-08-03T19:38:57.640 に答える
3

MVVM パラダイムを使用している場合は、ViewModel がモデルとビューの間のアダプターの役割を持つと考える必要があります。

ViewModel があらゆる点で UI の存在に完全に依存しないことは期待されていませんが、特定のUI には依存しないことが期待されます。

そのため、ViewModel はできるだけ多くのコンバーターの機能を持つことができます (そして持つべきです)。ここでの実際の例は次のようになります。

UI は、テキストが既定の文字列と等しいかどうかを知る必要がありますか?

答えがyesIsDefaultStringの場合は、ViewModel にプロパティを実装する十分な理由です。

public class TextViewModel : ViewModelBase
{
    private string theText;

    public string TheText
    {
        get { return theText; }
        set
        {
            if (value != theText)
            {
                theText = value;
                OnPropertyChanged("TheText");
                OnPropertyChanged("IsTextDefault");
            }
        }
    }

    public bool IsTextDefault
    {
        get
        {
            return GetIsTextDefault(theText);
        }
    }

    private bool GetIsTextDefault(string text)
    {
        //implement here
    }
}

TextBox次に、次のようにバインドします。

<TextBox x:Name="textBox" Background="White" Text="{Binding Path=TheText, UpdateSourceTrigger=LostFocus}">
    <TextBox.Resources>
        <Style TargetType="TextBox">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsTextDefault}" Value="False">
                    <Setter Property="TextBox.Background" Value="Red"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBox.Resources>
</TextBox>

TextBoxこれにより、フォーカスが失われるとテキストが ViewModel に反映され、 IsTextDefault. これを何度も、または多くのプロパティに対して行う必要がある場合は、 のような基本クラスを作成することもできますDefaultManagerViewModel

于 2009-08-09T11:55:49.693 に答える
1

完全に異なる方法は、INotifyPropertyChanged を実装せず、代わりに DependencyObject または UIElement から派生することです。

それらは DependencyProperty を使用してバインディングを実装します

e.NewValue != e.OldValue バインディングが変更されるべきではないため、チェックは冗長であると確信しています。また、バインディングを実装する方法があると信じているため、dependecyObject はテキストボックスであり、オブジェクトではありません...

WPF クラス (コントロールやユーザー コントロールなど) から既に継承している場合は編集してください。ほとんどの WPF はそのクラスから継承されるため、UIElement に変更する必要はありません。

次に、次のことができます。

using System.Windows;
namespace YourNameSpace
{
class PersonViewer:UIElement
{

    //DependencyProperty FirstName
    public static readonly DependencyProperty FirstNameProperty =
        DependencyProperty.Register("FirstName", typeof (string), typeof (PersonViewer),
                                    new FrameworkPropertyMetadata("DefaultPersonName", FirstNameChangedCallback));

    public string FirstName {
        set { SetValue(FirstNameProperty, value); }
        get { return (string) GetValue(FirstNameProperty); }
    }

    private static void FirstNameChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) {

        PersonViewer owner = d as PersonViewer;
        if (owner != null) {
            if(e.NewValue != e.OldValue && e.NewValue != "DefaultPersonName" ) {

                //Set Textbox to changed state here

            }
        }

    }

    public void AcceptPersonChanges() {

        //Set Textbox to not changed here

    }

 }
}
于 2009-08-11T20:53:55.957 に答える
1

ViewModelにIsFirstNameModifiedや などのブール値のプロパティを追加しIsLastNameModified、トリガーを使用して、これらのプロパティに従ってテキスト ボックスの背景を変更できます。または、bool から aBackgroundを返すコンバーターを使用して、これらのプロパティにバインドすることもできます...Brush

于 2009-08-03T19:49:33.173 に答える
0

最後の回答のバリエーションは、値がデフォルト値でない限り、常に変更された状態にあることです。

 <TextBox.Resources>
    <Style TargetType="{x:Type TextBox}">

        <Style.Triggers>
            <Trigger Property="IsLoaded" Value="True">
                <Setter Property="TextBox.Background" Value="Red"/>
            </DataTrigger>
        </Style.Triggers>

        <Style.Triggers>
            <DataTrigger Binding="{Binding RelativeSource Self}, Path=Text" Value="DefaultValueHere">
                <Setter Property="TextBox.Background" Value=""/>
            </DataTrigger>
        </Style.Triggers>

    </Style>
</TextBox.Resources>

于 2009-08-11T20:41:39.303 に答える