Pass a value between a Window and a page in WPF - c#

i am developing a software with WPF and i would like pass a parameter(textbox) between the Window(MainWindow) to a page(it is situated in a Frame) ...do you have any idea as do it?
Thansk so much my friends...
BB
EDITED :
Well i have a textbox in the MAINWINDOW with the Value "DB2012_2013" then the code of the frame is this one :
<Frame HorizontalContentAlignment="Stretch" LoadCompleted="frSample_LoadCompleted" Navigating="frSample_Navigating" VerticalContentAlignment="Stretch" x:Name="frSample" Background="{x:Null}" Margin="0,0,0,0" Source="{Binding SelectedItem.XamlFilePath, ElementName=CategoryTreeView, FallbackValue=Welcome.xaml, IsAsync=True}"/>
then when i choose the page to open i would pass the value of the textbox in the new page ... to use this value for some query to do ..

You can use DataContext and WPF Binding feature.
You can set DataContext belong to MainWindow.
Do you need pass data into Frame or UI component textbox?
<TextBox Name="textBox" Text="Text"></TextBox>
<Frame DataContext="{Binding ElementName=textBox,Path=DataContext}" Background="AliceBlue" Width="200">

You could make all pages implement an interface that has a property for the desired value.
public interface IPageWithValue
{
string MyValue { get; set; }
}
Whenever you change to the page, set the property value from the main window, whenever you leave the page, read the property.
Have your pages implement that interface.

Try this
App.Current.MainWindow.TextBoxName.Text

Related

WPF C# Binding Data from another Class

So I'm missing something simple or losing my mind. I am trying to reuse a class for multiple pages in a WPF application and bind the properties to the pages that instance it. I've tried setting the DataContext but I'm missing something. I'm loading the StockAnalysis page and then creating instance of the PriceChart class (this is the class for reuse) and I want the properties set in the PriceChart class to be the data to bind to the Stock.xaml.cs page. Even in setting the DataContext it is still looking for the StockAnalysis object. Why?
Stock.xaml.cs
public partial class StockAnalysis : Page
{
PriceChart PChart = new PriceChart();
public StockAnalysis()
{
InitializeComponent();
//Load The Data
List<Stock> HistoricalPrice = Database.GetPrices(ticker);
//Create The Charts
this.DataContext = PChart;
PChart.ShowPriceChart(HistoricalPrice);
}
}
Stock.xaml (Look at the Last TexBlock for the Binding of "LastPrice")
<Page x:Class="Stock.StockAnalysis"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
xmlns:local="clr-namespace:Stock"
mc:Ignorable="d"
d:DesignHeight="1000" d:DesignWidth="1200"
Title="Stock Analysis">
<StackPanel x:Name="LastClosePanel" Grid.Row="0" Grid.RowSpan="2" Grid.Column="5" Height="60" VerticalAlignment="Top" Margin="1,0,0,1" Style="{StaticResource LastCloseBackground}">
<TextBlock x:Name="LastCloseText" Foreground="OrangeRed" FontSize="12" HorizontalAlignment="Center" Margin="0,10,0,8">Last Close</TextBlock>
<TextBlock x:Name="LastCloseBind" Foreground="White" FontSize="16" HorizontalAlignment="Center" Text="{Binding LastPrice}"></TextBlock>
</StackPanel>
</Page>
PriceChart.cs (This is where I assign "LastPrice" in hopes to bind it to the TextBlock in stock.xaml.cs)
public class PriceChart
{
public string LastPrice { get; set; }
public void ShowPriceChart(List<Stock> FullList)
{
LastPrice = FullList[0].LastPrice.ToString("C");
//DO OTHER THINGS
}
}
The problem is that PriceChart doesn't implement any change notification. With the current code, this is how things will go when StockAnalysis gets created:
InitializeComponent() will create the TextBlocks and the binding. At this point, DataContext is null, so the binding will fail and the TextBlock stay empty.
this.DataContext = PChart will trigger a binding update (because DataContext is a DependencyProperty, which means it does support change notification). When the binding updates, it will pull the value of LastPrice, which is currently still empty.
ShowPriceChart will set the value of LastPrice, but because PriceChart doesn't support change notification, the binding doesn't know it needs to update, so the TextBlock stays empty.
To solve this, I would recomend your PriceChart implement the INotifyPropertyChanged interface per this article: How to: Implement Property Change Notification.
(Technically, moving PChart.ShowPriceChart(HistoricalPrice) before this.DataContext = PChart would also "solve" the problem, but only if you never need to update the bindings again after initialization.)

UWP simple Databinding not working

I have been following some training videos and created a simple app with UWP and C#, and using UWP Databinding, unfortunately passing data from a textbox to a class property just doesn't work. Nothing happens. No data is passed, no errors generated.
So my class(everything stripped to relevant code) is
public class ChangeCalc
{
public string GoodsCost { get; set; }
public string Amountpaid { get; set; }
Under page is
<Page.DataContext>
<local:ChangeCalc />
</Page.DataContext>
Under my 2 TextBoxes I have
<TextBox
x:FieldModifier="public"
Text="{Binding Amountpaid, Mode=TwoWay}"
TextWrapping="Wrap" />
So it is all there.
If I just call it under the button Click event in the codebehind it works OK. Data passes, code runs.
myChangeCalc.GoodsCost = txtCost.Text;
myChangeCalc.Amountpaid = txtPaid.Text;
When is the databinding initiated? What event, if any, is missing?
Thanks for your help.
There is nothing being passed through. yet with the click event to the same properties, it passes OK.
This is because when you use data binding, you just give a data model as DataContext in where the property can be found to the TextBox, you didn't actually pass any real data to the TextBox. And when you use button click event, you create an instance "myChangeCalc" of this data model and pass a real data like "txtPaid.Text" to the property "Amountpaid" of this instance.
silverfighter, you don't have to implement INotifyPropertyChanged (what do I know I can't get it to work) The instructions say : Changes to TextBox.Text are sent to a two-way bound source when the TextBox loses focus, and not after every user keystroke.
Yes, but this change is from binding target to binding source, if you want change from binding source to binding target here, you must implement the INotifyPropertyChanged interface on the source object so that the source can report changes through events that the binding engine listens for.
So, as an example here:
<Page.Resources>
<local:ChangeCals x:Name="ccData" Amountpaid="111" />
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" DataContext="{StaticResource ccData}">
<TextBox
x:FieldModifier="public"
Text="{Binding Amountpaid, Mode=TwoWay}"
TextWrapping="Wrap" Height="50" />
</Grid>
You can create a instance of your data model in the page resources, and set this resource as the DataContext of Binding.
Another example:
<TextBox
x:FieldModifier="public"
Text="{Binding Amountpaid, Mode=TwoWay}"
TextWrapping="Wrap" />
code behind:
public MainPage()
{
this.InitializeComponent();
this.DataContext = myChangeCalc;
}
public ChangeCals myChangeCalc = new ChangeCals { Amountpaid = "111", GoodsCost = "222" };
Any way, the binding source should be an instance of your data model(ChangeCals class). Since you used {Binding} here, I didn't show sample of using {x:Bind}, if you want to learn more about {x:Bind}, you can refer to {x:Bind} markup extension. For more info about binding and x:Bind, you can refer to Data binding in depth.

Binding to code behind from custom control

I have a GridView that has several buttons. One of them is defined by the following template:
<DataTemplate x:Name="SubjectItemTemplate">
<Canvas Width="340" Height="170" VerticalAlignment="Top">
<Controls:ThreeImageButton HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,0"
NormalStateImageSource="{Binding NormalImage}"
HoverStateImageSource="{Binding HoverImage}"
PressedStateImageSource="{Binding PressedImage}" Command="{Binding Path=NavigateToUnitsPage}"
CommandParameter="{Binding}" Canvas.Left="0" Canvas.Top="0">
</Controls:ThreeImageButton>
</Canvas>
</DataTemplate>
Now I have a custom control as you can see, called ThreeImageButton. The button works fine when I use it on its own. But when I have it in the DataTemplate it won't bind properties to the code behind.
Right now, I have
x:Name="MyThreeImageButton"
in the custom button definition. And I connect to the code-behind like this:
<TextBlock Text="{Binding ElementName=MyThreeImageButton, Path=NormalStateImageSource}"/>
(This is just a test to display the text, in the actual code I would assign an image source to another property that is referred to by an element).
Right now, nothing is displayed in the TextBlock. What is the correct binding syntax I'm supposed to use to reach my properties?
Thanks!
Edit: I am setting the variable in the InitializeComponent function and I am using SetValue on the DependencyProperty.
Edit: Let me add the following information to be more clear
Scenario I:
In DataTemplate for GridView:
<UserControl CustomParameter="Literal Text">
In UserControl:
<TextBlock Text="{Binding CustomParameter}">
in UserControl .cs: this.DataContext = this
works!
Scenario II:
In DataTemplate for GridView:
<UserControl CustomParameter="{Binding ValueFromDataItem">
In UserControl:
<TextBlock Text="{Binding CustomParameter}">
in UserControl .cs: this.DataContext = this
nope!
I see,
So setting up a two-way binding to a custom property in a user control can be tricky because a user control cannot bind to a CLR property. Not only that but setting the data context on a user control has an unexpected effect on the binding inside it.
You can solve these problems with a little slight of code. Basically back your CLR properties with dependency properties and set the data context on a child element instead of the root user control.
Take a look at this sample. Let's pretend you have the following MainPage. That MainPage will eventually use our custom user control. So let's set the stage.
Here's the code-behind:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.DataContext = new /* your view model */
{
Title = Guid.NewGuid().ToString(),
};
}
}
In the code above I am simulating a complex view model with a simple anonymous class. It would be silly for you to implement your own like this, but at the same time it is silly for me to build a simple sample with the complete scaffolding. I bring this up only so it does not confuse you - as it could look like I am suggesting this approach in prod.
Here's the XAML:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<local:MyUserControl Text="{Binding Title}" />
</Grid>
In the XAML above, there is absolutely nothing special. I already have reference to the user control in the local namespace and I simply declare it here.
Okay, now that we have a consumer of the control, it's worth pointing out that in testing developers can mistakenly think that their binding is working because they test with literal values. Literal values bind fine. It's binding from the underlying view model that hick-ups.
Let's say another thing, some developers tend to avoid dependency properties because the require a little more typing. People remember that [kbd]propdp[/kbd] is a handy Visual Studio snippet that stubs out a dependency property for you.
Take a look at this user control. It has two controls, a TextBox and a TextBlock which are there to demonstrate the OneWay and TwoWay functionality of this binding approach. We also implement INotifyPropertyChanged on the user control. For the most part, adding a view model in the case of a user control is overkill because the user control already acts like a view model. It's up to the developer, but it seems dumb to me.
Here's the code behind:
public sealed partial class MyUserControl : UserControl, INotifyPropertyChanged
{
public MyUserControl()
{
this.InitializeComponent();
}
// text property
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValueDp(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(MyUserControl), null);
// bindable
public event PropertyChangedEventHandler PropertyChanged;
void SetValueDp(DependencyProperty property, object value,
[System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
{
SetValue(property, value);
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
In the ode above, I have create a "Text" property and backed it with a dependency property. For a matter of reuse I have also implemented SetValueDp() which could be used again and again if I had more than a single property. Even though this demo has but one, I wanted to include this because the repetitive logic should certainly be abstracted out like this.
Here's the XAML:
<Grid Background="Black" DataContext="{Binding ElementName=userControl}">
<StackPanel>
<TextBox Text="{Binding Text, Mode=TwoWay}"
MinHeight="100" Padding="15" FontWeight="Light" FontSize="50" />
<TextBlock Text="{Binding Text}"
MinHeight="100" Padding="15" FontWeight="Light" FontSize="50" />
</StackPanel>
</Grid>
In the XAML above, I do nothing special insofar as binding. The syntax simply binds to the Text property using the Mode appropriate to the control. Just like you would do normally. However, what's worth noticing is that the DataContext is NOT set on the user control. Instead, it is set on the Grid. As a point of fact, any control in the tree other than the user control could be used like this. Just don't set the data context of the user control.
That is it by the way.
I have tested it to make sure it works. Demonstrating both one and two way binding is pretty handy here. I might even turn this into a blog in case other developers want to find it and don't discover this question. Thanks for your question!
Best of luck!
As the comments alluded to, your DataTemplate is placing the datacontext of the items to whatever object you are adding to your list. This is not the same as the surrounding user control's data context. If you want to reference that datacontext's commands, do the following in the DataTemplate's bindings:
{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.NormalImage}
What this is saying is to go out and find the user control ancestor and use its datacontext and then look for the NormalImage property. If you run into problems, check your output window for binding errors. It is very helpful in finding binding problems.

How to use a xaml object in another class

I have one class with a xaml which contains a label. I want to change content of this label from one different class.
for example i have a class mainwindow.xaml.cs with mainwindow.xaml and i want to handle the label of mainwindow.xaml from the newclass.cs.
How can i do this??
edit: i have this label in a grid and i want to change the content from another class:
<Label Content="" Panel.ZIndex="1" FontWeight="SemiBold" FontSize="16px" Name="lb1" Margin="0,0,0,0" VerticalAlignment="Bottom" Height="30" HorizontalAlignment="Right" Width="250" HorizontalContentAlignment="Right" VerticalContentAlignment="Top"/>
What I would do is something like this, I'm not sure if it's the most logical thing to do but it works for me.
In your newclass.cs :
Class Newclass
{
MainWindow main;
public Newclass(MainWindow win)
{
main = win;
main.label.content = "";
}
}
and then in your mainwindow.xaml.cs:
Newclass class = new Newclass(this);
Data binding and MVVM would be the most elegant solution.
But you can simply use code-behind.
Give the label a name <Label x:Name="myLabel"> so you can access it in your code with that name like any other variable.
You can then pass this variable to your newclass.cs and change its properties there.
you can use binding - or even better binding with MVVM pattern and viewmodel first.
but nevertheless, when asking a question you should post some code

Usercontrol databinding property changed MVVM

I am working with WPF and using data binding.
I would like to make a UserControl which has a property that could be used for data binding.
Also, I want to update some other property in the UserControl if the property changed.
For example,
public class MyControl : UserControl
{
....
....
....
....
public ViewStyles CurrentView
{
get { return (ViewStyles)GetValue(CurrentViewProperty); }
set
{
SetValue(CurrentViewProperty, value);
UpdateView();
}
}
public static readonly DependencyProperty CurrentViewProperty = DependencyProperty.Register("CurrentView", typeof(ViewStyles), typeof(ComboView));
....
.....
.....
.....
}
Problems comes:
A ViewModel is used and in which, there is a property ViewStyle which binded to the CurrentView in the above.
Another control combobox is also data-binded with ViewStyle in the ViewModel.
Actually, I want to use a combobox to choose the different view of my control. How to make it possible in MVVM?
I tried the above method. However, the UI (the different ViewStyles of MyControl) didn't change. It only change when I click on it using the mouse.
Thank you.
XAML: (MyControl)
<Views:MyControl Grid.Column="1" Grid.Row="1" Height="505" HorizontalAlignment="Left" Margin="2,0,0,0" Name="comboView1" VerticalAlignment="Top" Width="983"
ViewStyle="{Binding Path=CurrentView}" BorderThickness="5" BorderBrush="Black" ItemsSource="{Binding Path=Images}"
SelectedIndex="{Binding Path=CurrentIndex}" Foreground="White"
</Views:MyControl>
XAML: (ComboBox)
<ComboBox Margin="0,3,1,0" Width="178" HorizontalAlignment="Right" Name="ViewDDBox" FontSize="13" Foreground="#FFF6F3F3" Background="#FF444444"
BorderThickness="2" Height="23" VerticalAlignment="Top" Grid.Column="1"
ItemsSource="{Binding Path=ViewTypes}" IsEnabled="True" SelectedValue="{Binding Path=CurrentView, Mode=TwoWay}">
</ComboBox>
It is supposed that the view (some UI effect) will be changed of MyControl after choosing in the Combobox. But now, it only change when I click on MyControl using mouse.
The UpdateView() in your CurrentView property setter raises a HUGE red flag! You should never have any content other than SetValue in a dependency property setter, as certain aspects of xaml call the SetValue directly instead of going through the property. Always use the coerce property callback (if you want to validate the data before it's set) or the property changed callback (if you want to act after the property is changed, as I show in the example below).
You should do this instead:
public static DependencyProperty CurrentViewProperty =
DependencyProperty.Register("CurrentView", typeof(ViewStyles), typeof(ComboView),
new FrameworkPropertyMetadata(CurrentViewPropertyChanged));
private static void CurrentViewPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyControl mc = (MyControl)d;
mc.UpdateView();
}
Instead of binding the view, why not create a templated control and then bind the control's view to the property on your viewmodel?
You may also have to use data template triggers on your template to get the desired functionality.
Check out this article for help on template basics and this one for a more in depth discussion.

Categories