문제

"FirstName"및 "LastName"2 개의 속성이있는 클래스 EmployeeViewModel이 있습니다. 클래스는 또한 속성의 변화가있는 사전을 가지고 있습니다. (이 클래스는 inotifypropertychanged와 idataerrorinfo를 구현하면 모든 것이 괜찮습니다.

제 생각에는 텍스트 상자가 있습니다.

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

원래 값이 변경된 경우 텍스트 상자의 배경색을 어떻게 변경할 수 있습니까? 배경색을 설정하는 트리거를 만드는 것에 대해 생각했지만 무엇을 바인딩해야합니까? 나는 주를 바꾸 었는지 여부를 보유하는 모든 컨트롤에 대한 추가 속성을 만들고 싶지 않습니다.

고마워

도움이 되었습니까?

해결책

동일한 속성을 가진 멀티 핀딩을 두 번 사용하지만 바인딩 중 하나에 모드 = 일시가 있습니다. 이와 같이:

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>

추가 속성이나 논리가 필요하지 않으며 아마도 모든 것을 자체 마크 업 확장으로 랩핑 할 수 있습니다. 도움이되기를 바랍니다.

다른 팁

당신은 a를 사용해야합니다 가치 변환기 (문자열 입력을 색상 출력으로 변환) 가장 간단한 솔루션은 EmployeeViewModel에 하나 이상의 속성을 추가하는 것입니다. 당신은 일종의 a를 만들어야합니다 기본 또는 OriginalValue 재산과 그것에 대해 비교하십시오. 그렇지 않으면 "원래 가치"가 무엇인지 어떻게 알 수 있습니까? 원래 값을 비교할 수있는 것이 없다면 값이 변경되는지 알 수 없습니다.

따라서 텍스트 속성에 바인딩하고 입력 문자열을보기 모델의 원래 값과 비교하십시오. 변경된 경우 강조 표시된 배경색을 반환하십시오. 일치하는 경우 일반 배경색을 반환하십시오. 비교하려면 멀티 바인딩을 사용해야합니다. 이름 그리고 단일 텍스트 상자에서 함께.

나는 이것이 어떻게 작동하는지 보여주는 예를 만들었습니다.

<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 Name="textBox" Text="{Binding Path=DefaultString, Mode=OneTime}"
         Background="{Binding ElementName=textBox, Path=Text, Converter={StaticResource changedDefaultColorConverter}}"/>

MVVM 패러다임을 사용하는 경우 뷰 모델을 모델과 뷰 사이의 어댑터 역할을하는 것으로 간주해야합니다.

ViewModel이 모든면에서 UI의 존재에 대해 완전히 불가지론적일 것으로 기대되는 것은 아니지만, 특정한 UI.

따라서 ViewModel은 가능한 한 많은 변환기의 기능을 가질 수 있습니다. 여기서 실질적인 예는 다음과 같습니다.

UI가 텍스트가 기본 문자열과 같은지 알아야합니까?

대답이 있다면 , AN을 구현하는 데 충분한 이유입니다 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 초점을 잃고, 이로 인해 재 계산을 일으킨다 IsTextDefault. 이 작업을 여러 번 또는 많은 속성에 대해해야한다면, 당신은 같은 기본 클래스를 요리 할 수도 있습니다. DefaultManagerViewModel.

ViewModel 부울 속성에 추가 할 수 있습니다 IsFirstNameModified 그리고 IsLastNameModified, 트리거를 사용 하여이 속성에 따라 텍스트 상자가 배경을 변경하십시오. 또는 당신은 묶을 수 있습니다 Background 컨버터가있는이 속성에 Brush 부울에서 ...

완전한 다른 방법은 InotifyPropertyChanged를 구현하지 않고 대신 의존성 또는 Uielement에서 내려 오는 것입니다.

이벤트가 이벤트 핸들러와 사용자 E.Property 만 사용하여 Rigth Textbox를 찾을 수있는 이벤트를 사용하여 바인딩을 구현합니다.

나는 e.newvalue! = e.oldvalue 검사가 바인딩이 바뀌지 않아서 중복 될 것이라고 확신합니다. 또한 바인딩을 구현할 수있는 방법이있을 수 있으므로 PesencyObject는 텍스트 상자가 아니고 객체가 아닙니다 ...

편집 WPF 클래스 (제어 또는 UserControl과 같은)에서 이미 상속되면 괜찮을 것입니다.

그러면 다음을 가질 수 있습니다.

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

    }

 }
}

마지막 답변의 변형은 값이 기본값이 아닌 한 alwais가 수정 된 상태에있는 것일 수 있습니다.

 <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