Связывание данных с методом в WPF

У меня возникли проблемы с TextBox.Text свойства TextBox.Text к методу объекта. Идея заключается в том, чтобы позволить пользователю записать в TextBox имя файла и затем получить вывод TextBlock таким расширением.

class GetFileInfo
{
    public string GetFileExtension(string fileName)
    {
        return Path.GetExtension(fileName);
    }
}

Вот мой XAML:

<Window.Resources>
    <ObjectDataProvider x:Key="getFileInfo" MethodName="GetFileExtension" ObjectType="{x:Type local:GetFileInfo}">
        <ObjectDataProvider.MethodParameters>
            <sys:String>abc.text</sys:String>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

<StackPanel>
    <TextBox Name="textBox1">
        <TextBox.Text>
            <Binding Source="{StaticResource getFileInfo}" Path="MethodParameters[0]" BindsDirectlyToSource="True" UpdateSourceTrigger="PropertyChanged" />
        </TextBox.Text>
    </TextBox>
    <TextBlock Name="textBlock1" Text="{Binding Source={StaticResource getFileInfo}}"/>
</StackPanel>

По какой-то причине он ничего не делает. Кто-нибудь может указать на причины? Вот что я вижу на дизайнере и когда запускаю приложение:

alt text

И вот что происходит, когда я пытаюсь установить другой текст во время выполнения:

alt text Вот ошибка, выдаваемая de debugger при попытке установить другой текст во время выполнения:

Ошибка System.Windows.Data: 8: Невозможно сохранить значение от цели назад к источнику. BindingExpression: Path = MethodParameters [0]; DataItem = 'ObjectDataProvider' (HashCode = 2207369); целевым элементом является TextBox (Name = 'textBox1'); Свойство target имеет значение "Text" (тип "String"). ArgumentException: "System.ArgumentException: объект типа" MS.Internal.Data.PropertyPathWorker + IListIndexerArg "не может быть преобразован в тип" System.Int32 ". в System.RuntimeType.TryChangeType (значение объекта, связыватель Binder, культура CultureInfo, логическое значение needsSpecialCast) в System.RuntimeType.CheckValue (значение объекта, связыватель Binder, CultureInfo culture, invindingAttr BindingFlags, в System.Reflection.MethockguCaseCase). параметры, связыватель Binder, BindingFlags invokeAttr, культура CultureInfo, сигнатура сигнатуры) в System.Reflection.RuntimeMethodInfo.Invoke (объектный объект, BindingFlags invokeAttr, связыватель Binder, параметры Object [], CultureInfo культура, логические skipVisibilityChecks) в System.RuntimeMhofo.MunfoTimeTime.RoInfo.Mun Вызвать (Object obj, BindingFlags invokeAttr, Binder Binder, параметры Object [], CultureInfo culture) в System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder Binder, Object [] index, CultureInfo culture) в MS.Internal.Data.PropertyPathWorker.SetValue (Элемент объекта, значение объекта) в MS.Internal.Data.ClrBindingWorker.UpdateValue (значение объекта) в System.Windows.Data.BindingExpre ssion.UpdateSource (значение объекта) '

Ответ 1

Хорошо, кажется, что это ошибка при запуске WPF 4.0, как видно из комментариев здесь.

Woops, я был немного поспешным. пример работает отлично, как только вы его скомпилируете для рамки 3.5 (в VS 2010). Но если вы конвертируете его в проект WPF 4.0, метод WeightOnPlanet на ObjectDataProvider - это nolonger, вызываемый на odp2 при редактировании текстового поля. Я попытался найти любые новые атрибуты либо в Binding, либо ObjectDataProvider, но пока ничего не вышло...

При компиляции в 3.5 он отлично работает здесь.

Ответ 2

Пока можно использовать Binding для вызова метода и получения его возвращаемого значения, это не просто. Это гораздо проще привязать к свойствам и использовать комбинацию привязки и уведомления об изменении, чтобы получить результат, который вы ищете.

Создайте класс с двумя свойствами, Filename и Extension. Filename - это просто свойство строки чтения/записи. Extension - это свойство строки только для чтения, получатель которого вызывает метод, который вы пытаетесь вызвать.

Теперь сделайте этот класс реализованным INotifyPropertyChanged, потому что если свойство может меняться в коде, ему нужен способ сообщить привязку, что он это сделал. Сделать установщик атрибута Filename уведомлять привязки, что свойство Extension изменилось.

Добавьте Binding в TextBox, который привязывается к свойству Filename, используя режим TwoWay. Добавьте Binding в TextBox, который привязывается к Extension, используя режим OneWay по умолчанию.

Последовательность событий:

  • Пользователь вводит новый Filename в привязку TextBox и нажимает TAB.
  • TextBox теряет фокус.
  • Поскольку режим Binding TwoWay, и он использует поведение по умолчанию для обновления источника, когда цель теряет фокус, что он делает.
  • Binding обновляет источник, вызывая установщик Filename.
  • Сетчатель Filename поднимает PropertyChanged.
  • Binding обрабатывает PropertyChanged, рассматривает его аргумент и видит, что свойство Extension изменилось.
  • Binding вызывает getter Extension.
  • Геттер свойства Extension вызывает метод для определения расширения для Filename и возвращает его в Binding.
  • Binding обновляет свою цель TextBox новым значением Extension.

Это основная концепция привязки данных и шаблон MVVM. Как только вы это понимаете, он становится второй натурой, и разработка WPF становится примерно в десять миллионов раз легче.

Ответ 4

Для привязки данных требуется событие NotifyPropertyChanged, которое вызывается при обновлении источника. В этом случае вы захотите обернуть этот вызов функции в get/set следующим образом:



public class FileWrapper: System.ComponentModel.INotifyPropertyChanged{
    private string m_filename;

    public string FileExtension{
        get{ return GetFileExtension(FileName);}
    }

    public string FileName{
        get{ return m_filename;}
        set{ m_filename = value; OnPropertyChanged("FileName"); OnPropertyChanged( "FileExtension");
    }

    public string GetFileExtension( string filename){
        //implementation
    }

    public event System.ComponentModel.NotifyPropertyChangedEvent PropertyChanged = (a,b)=>{};

    protected void OnPropertyChanged(string property){
        PropertyChanged( this, new System.ComponentModel.PropertyChangedEventArgs( property ));
    }
}

Ответ 5

Установлен ли параметр DataContext? Вы указали значение для вашего TextBlock в "saadsas" (я могу только догадываться), что нарушило привязку ваших данных?