質問

2つのプロパティ" FirstName"を持つクラスEmployeeViewModelがあります。および「姓」。クラスには、プロパティの変更を含む辞書もあります。 (クラスはINotifyPropertyChangedおよびIDataErrorInfoを実装します。すべてが正常です。

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

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

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

Thx

役に立ちましたか?

解決

同じプロパティを持つ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>

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

他のヒント

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

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

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

<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>

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

/// <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}}"/>

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

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

したがって、ViewModelは可能な限り多くのコンバーターの機能を持つことができます(また、そうすべきです)。ここでの実用的な例は次のとおりです。

テキストがデフォルトの文字列に等しいかどうかをUIが知る必要がありますか?

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

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 などの基本クラスを作成することもできます。

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

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

DependencyPropertyを使用してバインディングを実装します イベントは、1つのイベントハンドラーとユーザーe.Propertyのみを使用して、正しいテキストボックスを見つけることができます

バインディングが変更されてはならないため、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

    }

 }
}

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

 <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>

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top