简体   繁体   中英

How can I assign text to a TextBlock that is read from a file when clicking a button

My app has to load a .txt file from the file system, read it and put its text into a TextBlock , but I don't know how to connect my Button to my view model so my text block that is bound to a property in it displays this text.

Let's repeat what I want my app to do:

  1. A user clicks on the load button and he chooses a .txt file
  2. The text from the file is assigned to the NumbersString property
  3. The text block loads this text from the NumbersString property

I dont know how to get step 2 to work.

XAML

<Button Name="load" Background="Pink" Click="load_Click">Load File</Button>

<TextBox x:Name="numbers1" Text="{Binding NumbersString, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True"/>

Code-behind XAML

There is a mistake my view model property NumbersString . It should be connected to the button.

public partial class MainWindow : Window
{
   public MainWindow()
   {
      InitializeComponent();
      this.DataContext = new numbersViewModel();
   }

   public void load_Click(object sender, RoutedEventArgs e)
   {
      OpenFileDialog openFileDialog = new OpenFileDialog();
      if (openFileDialog.ShowDialog() == true)
         NumbersString = File.ReadAllText(openFileDialog.FileName);
   }
}

View model

class numbersViewModel : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;

   private numbersModel _model;

   protected void RaisePropertyChanged(string propertyName)
   {
      PropertyChangedEventHandler evt = PropertyChanged;
      if (evt != null)
         evt(this, new PropertyChangedEventArgs(propertyName));
   }
   
   // iI want my text block to take the string from here
   public string NumbersString
   {
      get { return _model.numbersString; }
      set
      {
         if (value != _model.numbersString)
         {
            _model.numbersString = value;
            RaisePropertyChanged("numbers1");
         }
      }
   }
}

Model

private string model="";
public string numbersString
{
   get
   {
      return model;
   }

   set
   {
      model = value;
   }
}

You raise the property changed event for numbers1 in your NumbersString property, therefore the change for the wrong property (that does not even exist) is triggered, but that will not update the TextBox .

Adapt the property name in the call to RaisePropertyChanged . You can use nameof instead of a hardcoded string .

public string NumbersString
{
   get { return _model.numbersString; }
   set
   {
      if (value != _model.numbersString)
      {
         _model.numbersString = value;
         RaisePropertyChanged(nameof(NumbersString));
      }
   }
}

Since you are using a mix of code-behind and MVVM, you could set the NumbersString property in your event handler like this:

public void load_Click(object sender, RoutedEventArgs e)
{
   OpenFileDialog openFileDialog = new OpenFileDialog();
   if (openFileDialog.ShowDialog() == true)
      ((numbersViewModel)DataContext).NumbersString = File.ReadAllText(openFileDialog.FileName);
}

The last bit to make it work is that you never create or assign an instance of a numbersModel to the _model property on numbersViewModel . You could do that in the constructor.

public numbersViewModel(numbersModel numbersModel)
{
   _model = numbersModel;
}

An MVVM approach using commands

Instead of using event handlers for button clicks, you should use commands. You can copy the RelayCommand class that @aepot linked . First, you create an ICommand property in your numbersViewModel .

public ICommand LoadFile { get; }

RelayCommand implements the ICommand interface and delegates the execution logic to a method that you have to pass when creating it in the constructor of numbersViewModel :

public numbersViewModel(numbersModel numbersModel)
{
   _model = numbersModel;
   LoadFile = new RelayCommand(ExecuteLoadFile);
}

The ExecuteLoadFile method contains the logic for loading the file and reading its text. In practice, this would also violate MVVM priciples as this method is located in a view model and OpenFileDialog is a view type. You would extract this part into a service with an interface, so that the view model does not know about its implementation, but that is beyond the scope of this question.

private void ExecuteLoadFile(object obj)
{
   var openFileDialog = new OpenFileDialog();
   if (openFileDialog.ShowDialog().GetValueOrDefault())
      NumbersString = File.ReadAllText(openFileDialog.FileName);
}

Finally, bind the Command property on your button to the LoadFile command.

<Button Name="load" Background="Pink" Content="Load File" Command="{Binding LoadFile}"/>

With these changes you can remove the event handler from your MainWindow .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM