WPF-Binding is broken when View is closed and reopened - wpf

I have a View (MainWindow.Xaml) which has a datacontext set to the MainWindowViewModel and I open it from the MainUIService like the code below.
public class MainUIService
{
void IMainUIService.Show()
{
var viewModel = ViewModelSource.Create(() => new MainWindowViewModel());
var mainUI = new MainWindow();
mainUI.DataContext = viewModel;
System.Windows.Application.Current.MainWindow = mainUI;
mainUI.Show();
}
}
My requirement is to close and Reopen the View from the MainWindowViewModel.Now the problem here is none of the bindings are working.I was trying to set the text for a textblock inside the MainWindow.xaml after ReOpening it.
<TextBlock x:Name="CurrentUserName" Padding="2" Background="{Binding
EnvironmentBackgroundColor}" Foreground="White" Text="{Binding UserName}"/>
I tried INotifyPropertyChanged,Mode=2way,IsAsyn=True and various solutions from internet,but nothing seems to work.
Is there any way I can achieve this?Please help

Related

Binding a button in WPF using PRISM DelegateCommand

I am just starting to learn WPF using the PRISM library. Please help me to solve one question. How to bind a button using DelegateCommand?
In the code behind everything is fine. In the MVVM code I can't get it to work.
Thanks.
My code in XAML:
<UserControl x:Class="Panel.Modules.DockingManager.DockingManagerPanel.DockingManagerPanelPrism"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
prism:ViewModelLocator.AutoWireViewModel="True">
<Grid>
<Button x:Name="button"
Command="{Binding LoadAllFiles}"
CommandTarget="{Binding ElementName=textBox}"
Height="24" Width="24">
</Button>
<TextBox x:Name="textBox" </TextBox>
</Grid>
</UserControl>
And my code in ViewModel:
public class DockingManagerPanelViewModel : BindableBase
{
public DelegateCommand LoadAllFiles { get; set; }
public DockingManagerPanelViewModel()
{
LoadAllFiles = new DelegateCommand(LoadTxt);
}
private void LoadTxt()
{
var dialog = new Microsoft.Win32.OpenFileDialog();
dialog.Multiselect = true;
dialog.FileName = "Document";
dialog.DefaultExt = ".txt";
dialog.Filter = "Text documents (*.*)|*.*";
bool? result = dialog.ShowDialog();
if (result == true)
{
StreamReader sr = new StreamReader(File.OpenRead(dialog.FileName));
sr.ReadToEnd();
}
}
}
You are reading the text but not doing anything with what you read. You need to read it into some sort of string property and then bind the TextBox to that property.
Also you are failing to use a using statement on the StreamReader.
The good news is that you don't need to use StreamReader. You can just use the much simpler File.ReadAllText function.
First, add this to your view model. A public property exposing the read text. It uses BindableBase's SetProperty to raise the proper event when the value changes
public string LoadedText
{
get => _loadedText;
set => SetProperty(ref _loadedText, value);
}
private string _loadedText = string.Empty;
Next, change the last few lines of your LoadTxt function to do this instead of using StreamReader
if (result == true)
LoadedText = File.ReadAllText(dialog.FileName)
Finally, change the TextBox in XAML to look like this. I made it one way becase I assume you do not want the user editing inside of it, to change the value in the backing LoadedText property. A better approach might be to just use a TextBlock instead of a TextBox
<TextBox x:Name="textBox" Text="{Binding LoadedText, Mode=OneWay}"/>

How to show floating virtual keyboard (user control) in MainWindow when an input control (from another user control) has been set to focus in WPF?

I have been doing development work in WPF application which uses an MVVM pattern for a couple of days now. I'm very new to WPF and MVVM pattern as well.
In my scenario, I have a user control view (named EPayView.xaml) which has a textbox that will accept a phone number. The view has a corresponding viewmodel (named EPayViewModel.cs). In the MainWindow.xaml, I have a user control (floating virtual keyboard) which is derived from namespace controls WpfKb.Controls. The MainWindow.xaml also has a corresponding viewmodel (named MainViewModel.cs)
Having said that, I have done research on how to use attached dependency properties which lead me to this solution. Set focus on textbox in WPF from view model (C#) which I believe this is where I could bind the property IsFocused in the textbox of EPayView.xaml.
Below are the codes that I have already incorporated in my solution.
EpayView.xaml (textbox xaml markup)
<TextBox Text="{Binding PhoneNo}" Grid.Row="5" Margin="10,0,10,0" VerticalContentAlignment="Center" FontSize="12" x:Name="Email" behaviors:FocusExtension.IsFocused="{Binding IsFocused, Mode=TwoWay}"/>
MainWindow.xaml (xaml markup)
<Window x:Class="SmartPole540.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:WpfKb.Controls;assembly=SmartPole.WpfKb"
xmlns:wpf="clr-namespace:WebEye.Controls.Wpf;assembly=WebEye.Controls.Wpf.WebCameraControl"
xmlns:utilities="clr-namespace:SoltaLabs.Avalon.Core.Utilities;assembly=SoltaLabs.Avalon.Core"
xmlns:userControls="clr-namespace:SoltaLabs.Avalon.View.Core.UserControls;assembly=SoltaLabs.Avalon.View.Core"
xmlns:square="clr-namespace:SmartPole.View.Square;assembly=SmartPole.View"
xmlns:view="clr-namespace:SmartPole.View;assembly=SmartPole.View"
Title="CitiPulse"
WindowStartupLocation="Manual"
PreviewMouseLeftButtonDown="Window_PreviewMouseLeftButtonDown"
Name="mainWindow">
<userControls:RollPanel.BottomContent>
<square:SquareView Canvas.Top="1010" DataContext="{Binding DataContext.SquareViewModel,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type userControls:RollPanel}}}"/>
</userControls:RollPanel.BottomContent>
<controls:FloatingTouchScreenKeyboard
x:Name="floatKb" Width="500" Height="250" PlacementTarget="{Binding ElementName=MainGrid}"
Placement="Center" AreAnimationsEnabled="False" Visibility="Visible"
IsOpen="{Binding IsChecked, ElementName=kbButton}"/>
</Window>
In the above code, the user control RollPanel.BottomContent host the EPayView.xaml view inside another view which is RollPanel.xaml
EpayViewModel.cs contains the static class FocusExtension for the IsFocused attached property (refer to this solution - Set focus on textbox in WPF from view model (C#)). And, EPayViewModel.cs already implemented INotifyPropertyChanged which is wrapped inside a concrete class ObservableObject that accepts type of T. This is also same with MainViewModel.cs
public class EPayViewModel : ObservableObject<EPayViewModel>, IPaymentViewModel, IActiveViewModel
{ ... }
public class MainViewModel : ObservableObject<MainViewModel>
{ ... }
As such, my goal is that when the textbox in EPayView.xaml has the focus, the floating virtual keyboard (floatKb) in the MainWindow.xaml will be shown.
I'm stuck on how to proceed (I was thinking if a call to FocusExtension static class in EPayViewModel inside my MainViewModel.cs will suffice?), any help is greatly appreciated.
Cheers,
As AnjumSKhan already said, to react to some event in a MVVM way, you'll have to use Command. Command can be called within an EventTrigger, you will need to add a Reference to System.Windows.Interactvity component.
Let's assume you have a simple View and View Model and you need to show this View when the TextBox in a MainWindow got focus.
View (NewWindow.xaml)
<Window x:Class="My.NewWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="NewWindow" Height="300" Width="300">
<TextBlock Text="{Binding Message}"/>
View Model
public class NewWindowViewModel
{
private string _message;
public string Message
{
get { return _message; }
set { _message = value; }
}
}
You also have a MainWindow, it is a main view for an app and it contains the target TextBox. You may see that there is an EventTrigger added to the TextBox and it has a property InvokeCommandAction which is binded to the MainWindowViewModel's command called ShowCommand.
Main Window
<Window x:Class="My.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" Title="MainWindow" Height="350" Width="525">
<TextBox Height="40" Text="{Binding Text}">
<Interactivity:Interaction.Triggers>
<Interactivity:EventTrigger EventName="GotFocus">
<Interactivity:InvokeCommandAction Command="{Binding ShowCommand}"/>
</Interactivity:EventTrigger>
</Interactivity:Interaction.Triggers>
</TextBox>
In the Show method of MainWindowViewModel NewWindow view is created and got new NewWindowViewModel instance as a DataContext. RelayCommand class is presented in my answer to this question
MainWindowViewModel
public class MainWindowViewModel
{
private string _text;
public string Text
{
get { return _text; }
set { _text = value; }
}
private ICommand _increaseCommand;
public ICommand ShowCommand
{
get
{
if (_increaseCommand == null)
{
_increaseCommand = new RelayCommand(
p => true,
Show);
}
return _increaseCommand;
}
}
private void Show(object obj)
{
var w = new NewWindow();
var nvm = new NewWindowViewModel();
nvm.Message = "Test";
w.DataContext = nvm;
w.Show();
}
}
What is left is to create a new MainWindowViewModel and setup a DataContext for MainWindow.
public MainWindow()
{
InitializeComponent();
var mvm = new MainWindowViewModel();
mvm.Text = "Focus me!";
DataContext = mvm;
}
Hope it will help.

How to bind an ItemsControl to a dependency property of a usercontrol?

Trying to understand this better.
I have an ItemsControl defined in my mainview something like this
<ItemsControl Grid.Column="0" Grid.Row="2"
ItemsSource="{Binding Notes}"
ItemTemplate="{Binding Source={StaticResource MyParagraph}}"
>
</ItemsControl>
in which I would like to use a DataTemplate:
<UserControl.Resources>
<DataTemplate x:Key="MyParagraph">
<v:InkRichTextView
RichText="{Binding ?????? "
</DataTemplate>
</UserControl.Resources>
The InkRichTextView is a view with a dependency property, RichText, being used to pass a paragraph from the ObservableCollection(InkRichViewModel) Notes in the mainview to the user control. That is, this works correctly for one paragragh:
<v:InkRichTextView RichText ="{Binding Path=Note}" Grid.Column="0" Grid.Row="0" />
where Note is defined as a paragraph in the MainView.
The problem is, how do I write the DataTemplate and the ItemsControl such that the ItemsControl can pass each paragraph from the observablecollection to the dependency property RichText in the InkRichTextView?
Thanks for any guidance.
(I hope this is understandable!)
Items control:
<ItemsControl x:Name="NotesItemsControl" Grid.Column="2" HorizontalAlignment="Center">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<local:InkRichTextView RichText="{Binding Note}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Code behind:
class InkRichViewModel : System.ComponentModel.INotifyPropertyChanged
{
#region Note (INotifyPropertyChanged Property)
private string _note;
public string Note
{
get { return _note; }
set
{
if (_note != value)
{
_note = value;
RaisePropertyChanged("Note");
}
}
}
#endregion
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string p)
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(p));
}
}
}
public MainWindow()
{
InitializeComponent();
var item01 = new InkRichViewModel() { Note = "Note 01", };
var item02 = new InkRichViewModel() { Note = "Note 02", };
var item03 = new InkRichViewModel() { Note = "Note 03", };
var item04 = new InkRichViewModel() { Note = "Note 04", };
var item05 = new InkRichViewModel() { Note = "Note 05", };
var itemList = new List<InkRichViewModel>()
{
item01, item02, item03, item04, item05,
};
NotesItemsControl.ItemsSource = itemList;
}
How it looks at runtime:
Is that what you're looking for?
Based on what you describe, it seems that each item in your ItemsControl is a paragraph, the very object you want to assign to the InkRichTextView.RichText property. Is that correct?
If so, keep in mind that within the item template, the data context is the collection item itself - thus, the path you are looking for does not refer to a property of the data context, but to the data context itself.
That is done with the dot (.) path:
<v:InkRichTextView RichText="{Binding .}"/>
I'm posting this as an answer, although the credit goes to O.R.Mapper and Murven for pointing me in the right direction. My post is to help anyone else just learning this.
In very simple terms, the ItemControl performs a looping action over the collection in its ItemsSource. In my case the ItemsSource is a collection of type InkRichViewModel. (Hence the question from Murven). In its looping action, the ItemsSource will create objects from the InkRichViewModel. (Thus, my usercontrol now has an individual datacontext!) Each of these objects will use the ItemTemplate for display. So to simplify things, I moved the DataTemplate from the UserControl Resources to within the ItemControl itself as:
<ItemsControl Grid.Column="0" Grid.Row="2"
ItemsSource="{Binding Notes}"
>
<ItemsControl.ItemTemplate>
<DataTemplate>
<v:InkRichTextView RichText="{Binding Note}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Now that each of my usercontrols has its own datacontext being assigned by the ItemsControl, the Output window (VS2010) now shows the binding errors. Fixing these errors leads to a working solution.
Hope this helps other newbies like myself. Thanks everyone.
(Ooops! Just saw the answer from Murven but I'll leave this if it helps somebody to understand.)

WPF Renamed Property Doesn't Propagate to XAML

I'm a little new to WPF so bear with me. I have a property that is bound in my XAML, but if I rename it (right click --> Refactor --> Rename) in the .cs file it doesn't propagate to the XAML. Am I doing something wrong?
EDIT
Here's my code behind:
private string _selectedItem = null;
public string SelectedItemName
{
get { return _selectedItem; }
private set
{
if (_selectedItem != value)
{
_selectedItem = value;
OnPropertyChanged();
}
}
}
Here's my XAML:
<TextBox HorizontalAlignment="Left" Height="23" Margin="307,287,0,0" TextWrapping="Wrap"
Text="{Binding SelectedItemName}" VerticalAlignment="Top" Width="120" Name="txtTest2" />
Your setter needs to be public. WPF binding system can't change the text when you type into TextBox. The refactoring is never meant to change XAML files. Download ReSharper if you want to have such functionality.

How to make the URL in textblock be clickable?

The content of the textblock is imported from a web service, but somehow there is a URL.
Is it possible to make it a link?
Thanks.
Sounds like you want a LinkLabel control. I've used that control with some modifications in my Silverlight Twitter Badge to mix the text and links that show up in tweets.
If you just have a TextBlock with a link only and want that clickable then you just set the cursor to be a hand and add an event handler for the MouseLeftButtonDown event that would navigate to the value of the TextBox.
Xaml:
<TextBlock Text="http://www.microsoft.com" Cursor="Hand" TextDecorations="Underline" MouseLeftButtonDown="TextBlock_MouseLeftButtonDown" />
Code:
private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var txt = ((TextBlock)sender).Text;
System.Windows.Browser.HtmlPage.Window.Navigate(new Uri(txt, UriKind.Absolute));
}
You could do something like the following; however this makes use of a Label and not a textblock.
In your XAML you do the following:
<dataInput:Label Grid.Row="2">
<ContentPresenter>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Hello world"/>
<HyperlinkButton x:Name="Test" NavigateUri="{Binding Path=URI}" Content="This is a url"/>
</StackPanel>
</ContentPresenter>
</dataInput:Label>
and in your code behind you add the following dependency property and set the datacontext to the page itself
public static readonly DependencyProperty URLProperty =
DependencyProperty.Register("URI", typeof(Uri), typeof(MainPage), null);
public Uri URI { get
{
return (Uri)GetValue(URLProperty);
}
set
{ SetValue(URLProperty, value); }
}
This code sets the dependency property for the binding to the URL;
public MainPage()
{
InitializeComponent();
URI = new Uri("/Home", UriKind.Relative);
DataContext = this;
}
This code creates a new URI and binds it to the variable. It also sets the data context to the page itself.

Resources