WPF initialization issue - c#

I have a class MyWindow which inherits from Window. Within MyWindow, I have the following method to execute once my OK button is clicked:
private void OKButton_Click(object sender, RoutedEventArgs e)
{
var be = NameBox.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
this.Close();
}
XAML:
<Button Content="OK"
Click="OKButton_Click"
HorizontalAlignment="Left"
Margin="175,473,0,0"
VerticalAlignment="Top"
Width="75"
RenderTransformOrigin="-0.04,0.5"/>
In a separate class where I initialize my UI window, I say
MainWindow window = new MainWindow(ViewModel);
window.Show();
However, as soon as window.Show() is executed, the subsequent code is executed and I cannot actually interact with my window to do what I need to do. I feel like this is just a misunderstanding in how to actually use WPF in a larger context...any help?

Window.ShowDialog is what is needed to view the page. But one doesn't get the binding information as you did; which should be changed as well.
When the textbox loses focus it will update the binding so the code
var be = NameBox.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
is not needed. (Is this a leftover form winform programming?) So I suggestion one not update a binding as such.
The only possible thing to do if the binding is not updated is to change the binding to use the mode of TwoWay which ensures a back and forth data transfer between the variable bound to and the textbox on the screen.

Related

Simple TextBox Text Binding Fails WPF

We are converting an app from Silverlight to WPF. It's a fairly complex app, but the code sharing is about 95% +. The XAML is pretty much all the same except for XML namespace definitions etc. About 90% of the app now works but there are a few glaring issues that are puzzling me. One is this binding issue.
We have a model object called TaskInfo. It has a property called TaskNo. in Silverlight and WPF we bind to this property like this
<TextBox IsReadOnly="True" Grid.Column="0" Grid.Row="0" Margin="1" Text="{Binding Path=TaskNo}" Height="28" Background="#CAECF4" VerticalAlignment="Center" VerticalContentAlignment="Center" />
In both WPF and Silverlight the TaskNo is correctly displayed when the TaskInfo model is first set as the DataContext. In Silverlight, if we create a new TaskInfo, send it to the server for saving, and return the model with a new TaskNo, the TaskNo is successfully displayed. But, in WPF, it just displays 0 when the saved TaskInfo is returned from the server. There is some issue with binding. This is the binding error I see in the output window:
System.Windows.Data Information: 10 : Cannot retrieve value using the
binding and no valid fallback value exists; using default instead.
BindingExpression:Path=TaskNo; DataItem=null; target element is
'TextBlock' (Name=''); target property is 'Text' (type 'String')
I inspected the visual tree and the TextBox's DataContext is set to the TaskInfo as expected.
So, I turned off binding and tried this code. It's the event handler for the DataContextChanging on the TextBox. This code works fine. When a new task is saved and returned, the TaskNo successfully displays here:
private void TaskNoBox_DataContextChanging(object sender, DependencyPropertyChangedEventArgs e)
{
var task = TaskNoBox.DataContext as TaskInfo;
if (task == null)
{
throw new Exception("Ouch!");
}
TaskNoBox.Text = task.TaskNo.ToString();
}
To further debug this problem, I added this event handler for the GotFocus event on the text box. So, after the task has been saved on the server side and has been returned and set as the DataContext, I click inside the control to fire this event handler. When I step through this code, I can see that the DataContext is correct, and has the correct TaskNo. Calling this code still doesn't cause the binding to occur.
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
var textBox = (TextBox)sender;
var be = textBox.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
be.UpdateTarget();
}
TextBox Text binding property:
DataContext of TextBox's properties:
How do I make sense of this binding error? What are the binding gotchas between Silverlight and WPF? Do I need some kind of workaround? Why is binding not working?
Binding in WPF never updates if the previous DataContext is equivalent to the new DataContext according to the Equals method.
The difference between Silverlight and WPF seems to be that when the DataContext changes, WPF seems to use the Equals method to evaluate difference between objects while Silverlight uses the reference. That means that WPF is the same as Xamarin.Forms.
I tried this code, and it causes the TaskNo to display correctly. I think what is happening is that because the previous DataContext was equivalent to the new DataContext when Equals is called. So, this works around the problem.
private async void TaskPageHeader_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
TaskNoBox.DataContext = new object();
TaskNoBox.DataContext = CurrentTask;
}

XAML Update UI INotifyPropertyChanged

Background:
I have an application that has list of CheckBoxes and Button.
If the user selects a (or multiple) CheckBox and Click on the button, the Button event handler checks which CheckBox is checked. Based on that, it runs a process (ie. gpupate).
Then, I have an image (Visibility = "hidden") next to CheckBox in XAML. After the button is clicked, the code behind sets it to Visibility.Visible.
After the process is done, the Source of the image is changed to a different image. Bascically, the first image shows the process is running, second image is a check showing its completed.
I am trying to implement INotifyPropertyChanged Interface, so the UI is updated automatically after I change the visibility. Sometimes, UI is not updated after the the visibility is changed because there are number of CheckBoxes.
However, since I am not using any property, I cannot really bind it to something (or may be I am missing something) and INPC interface.
How can I implement the interface (or similar functionality).
XAML Code
<StackPanel Orientation="Horizontal">
<Image x:Name="oneImage"
Source="{StaticResource inProcessImage}"
Visibility="Hidden" />
<CheckBox x:Name="oneCheckBox"
Content="CheckBox"
Style="{StaticResource normalCheckBox}"/>
</StackPanel>
Code Behind inside Button Event Handler
if (oneCheckBox.IsChecked ?? false)
{
oneImage.Visibility = Visibility.Visible;
await Task.Run(() =>
{
//run GPUpdate
});
deleteHistoryImage.Source = (ImageSource)Resources["doneCheckImage"];
}
I do not have anything regarding the implementation of interface because I do not know what do I need to bind Visibility modifier with.
This is not what you're looking for, but it will update the GUI manually.
public void UpdateUI()
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
}
call UpdateUI(); after you change the visibility.

How to build my own close button?

I have a wpf application with a MVVM. I am trying here to build my own close button. Based on this answer Creating a custom Close Button in WPF I added a button event handler in the View(xaml.cs) code. However, it is not recognizing the Close(); call (doesn't exist in the context - Can't resolve symbol).
Also I tried the other answer and added Command and CommandParameter into my button's xaml. But the function behind is not getting hits. In How to bind Close command to a button using the RelayCommand also my wpf is not recognizing RelayCommand. Then How can I use the RelayCommand in wpf said that I have to write it myself(really?). I remember there was a simple way similar to just set an event handler for the button and call Close();. But, how can I do that or why it is not working for me?
View code:
private void closeButton_Click(object sender, RoutedEventArgs e)
{
// I want to call close the whole app on button click
//Close(); is not recognized
}
private void performMainCloseButtonCommand(object Parameter)
{
// This doesn't get hits on button click
Window objWindow = Parameter as Window;
objWindow.Close();
}
Button XAML:
<Button x:Name="closeButton" RenderTransformOrigin="0.5,0.5" Padding="0" Margin="701,0,0,0" BorderThickness="0" Click="closeButton_Click" Command="{Binding MainCloseButtonCommand}" CommandParameter="{Binding ElementName = mainWindow}" Height="45" Width="45" >
<StackPanel Height="45" Width="45">
<Image x:Name="closeButtonImage" Margin="0" Source="/ProjectName;component/Resources/x.fw.png" Height="33"/>
<TextBlock Text="Close" Width="36" Padding="6,0,0,0" HorizontalAlignment="Center" Height="13" FontSize="10"/>
</StackPanel>
</Button>
Close isn't recognized in your event handler because there is probably no method called Close in your current class. If you want to call main window's close method you can use:
private void closeButton_Click(object sender, RoutedEventArgs e)
{
Application.Current.MainWindow.Close();
}
Above is not a good way to do this and does not align with MVVM pattern. Which relates to your second question. Without seeing remaining part of your code, its hard to say why command binding isn't working. My guess you haven't wired up the commands properly for it to fire. You will need to ensure that you have created your RelayCommand instance and your command properties are correctly set.

How to remove a control from window programmatically?

I have a window with a button in it, and I need to remove it OR not depending on the argument passed to the window:
public MainWindow(bool removeControl)
{
InitializeComponent();
if (removeControl)
{
//code to remove the button
}
}
In the XAML file I declare a normal button:
<Button Width="120" Height="25" Content="Click" Name="ClickButton"></Button>
I know this can be done by doing the reverse thing which means add the button depending of the Boolean parameter, but I need to do so.
You can do:
mybutton.Visibility = Visibility.Collapsed;
...or if you really want it to be removed from the "logical tree"...then it all depends what "container"/parent that Button is in, in how you remove it.
Disconnecting an element from any/unspecified parent container in WPF
Remove Control from Window in WPF
http://joe-bq-wang.iteye.com/blog/1613370

Access XAML controls from C# code-behind

I have two files in my VS project: Custom.xaml and Custom.cs
In my XAML file, I have the following text boxes:
<TextBox x:Name="TextBox1" Text="{Binding Value, Mode=TwoWay}" Foreground="Black" Background="Green" SelectionChanged="TextBox1_SelectionChanged" />
<TextBox x:Name="TextBox2" Text="{Binding Value, Mode=TwoWay}" Foreground="Black" Background="Green" SelectionChanged="TextBox2_SelectionChanged" />
In my .cs, I have the following method:
void TextBox1_SelectionChanged(object sender, RoutedEventArgs e)
{
TextBox t = e.Source as TextBox
}
I can successfully hit the event handler above. Then, I can grab TextBox1 and it's properties by using e.Source, but I would like to access TextBox2 and it's properties.
As a sidenote, the .cs file is just a C# class that I am referencing, not a xaml.cs. Additionally, I understand that I could implement this via a UserControl, but cannot do that in this scenario for reasons that are outside the scope of this post.
Please advise on how I can get/set properties of TextBox2.
Thanks.
EDIT: Any other input on this? As a workaround, I've added an event handler called TextBox2_Loaded, and then set e.Source to an instance variable. Then, in TextBox1_SelectionChanged, I can access the instance variable. Would really like to just target the control directly (ex. TextBox2.IsEnabled). I must be missing a declaration or inheritance somewhere. Can't even find the control using FindName.
Alright, so I apparently had left out a critical component in this post... My TextBox controls are inside of DataTemplate controls. From my research, the TextBox controls cannot be accessed when inside of DataTemplate controls. I really didn't think that would matter, but I guess the instance variables are not created when this scenario exists.
If I've interpreted this incorrectly, please provide input. For now, I've gone ahead and added a Loaded event and defined my TextBox controls as instance variables so that I can access them and change properties when other activities occur.
Thanks for everyone's input.
As long as you have set a namein the XAML, you can access it directly by name (The XAML compiler will create an instance variable for you.)
void TextBox1_SelectionChanged(object sender, RoutedEventArgs e)
{
TextBox t = e.Source as TextBox
TextBox2.Text = "Whatever";
}
This just happened to me. I had to close my solution and reopen it.

Categories

Resources