<EventSetter Event="KeyDown" Handler="OnTestDown" />
I am having a weird experience where if I have an EventSetter in my XAML I can't make live UI changes e.g. If I change the UI background from green to Red while the EventSetter is in the XAML and I am in debug mode the background does not change while the app is running but if I remove the EventSetter while debugging the UI background updates as expected. This is only an issue on some laptops.
Related
I'm sorry for this being so wordy, but I want to make the situation perfectly clear. Please, if you are a WPF pro, take a look.
There are two CollectionViewSource bound to ItemsControls that use UserControl Views to display either StackPanels or custom Buttons. There is one for each side shown in the screenshot below. The problem I'm encountering is that when the parent collection property is set, all of the buttons in the DataTemplate view are disabled. Even the 2 buttons higher up are having the same problem even though they worked before my recent edits.
If I click on the form, or press any key, the buttons enable. As soon as the property is reset to a newly edited and sorted collection, they disable again. Rinse and repeat. This is what it looks like. The first frame is how it starts (gray using StackPanel), the 2nd is what it looks like when the RFS button is clicked, and the 3rd frame is what happens when I click anywhere or press a key.
I've been going in circles trying out things. The only thing that seems to work is a code-behind workaround that sets focus to one thing and then back. However, that would not be good for the user if they are trying to use one of the other dashboard items.
Since the WPF for all of this is very massive, I'll try to include just the relevant parts. These are the ItemsControls on the TabItemControl (UserControl).
<!-- BID (SELL) DEPTH -->
<ItemsControl Grid.Row="0" Grid.Column="0" x:Name="bidDepthList" ItemsSource="{Binding Source={StaticResource BidDepthCollection}}"
Visibility="{Binding Path=IsMultilegEnabled, Converter={StaticResource CollapsedConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type viewmodels:DepthLevelViewModel}">
<v:DepthLevelRowView x:Name="BidDepthLevelRowViewControl" DataContext="{Binding}" HorizontalAlignment="Center" Margin="1,0,1,3" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- ASK (BUY) DEPTH -->
<ItemsControl Grid.Row="0" Grid.Column="1" x:Name="askDepthList" ItemsSource="{Binding Source={StaticResource AskDepthCollection}}"
Visibility="{Binding Path=IsMultilegEnabled, Converter={StaticResource CollapsedConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type viewmodels:DepthLevelViewModel}">
<v:DepthLevelRowView x:Name="AskDepthLevelRowViewControl" DataContext="{Binding}" HorizontalAlignment="Center" Margin="1,0,1,3" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The view being used has 4 "controls" inside of a grid. Only one of them is displayed at a time depending on the state (RFS OFF/RFS ON) and which side they are on (Sell/Buy). The others are collapsed. As you can see, this is fine.
The only common factor between them is that they have their Command set, as do most of the controls at the top that are disabling/enabling correctly. The fact that the buttons enable correctly if any mouse or keyboard action is taken tells me that the CanExecute handler is working, just not immediately. The other controls started working after I made these changes, but then the big buttons started misbehaving like the depth buttons have been doing.
I've tried using CommandManager.InvalidateRequerySuggested(); after altering the collections, but that didn't help.
NOTE: This is also happening even for something as simple as this:
<Button x:Name="TestBuyButton" Command="{x:Static ptcommands:OrderCommands.Buy}" CommandTarget="{Binding RelativeSource={RelativeSource Self}}" Content="Test Buy" />
I know the booleans are set correctly because I added test CheckBoxes to display the current value with IsChecked. And, they all enable, including the extremely basic Button, as soon as any input action is taken.
Is there something else I'm missing or a different approach I can take?
EDIT: I ended up using the Dispatcher to invoke my display update routine from the event thread over to the UI thread. The boolean values get set, but WPF still didn't requery the Command. BUT.. the CommandManager.InvalidateRequerySuggested() call then worked! The only thing I don't like about that is it sounds like a broadcast invalidation. I don't want all commands to be requeried. I just want the Buy and Sell commands to requery. I've tried all sorts of weirdness trying to get just those to work, but nothing has worked so far other than the global.
EDIT 2: It appears as though the InvalidateRequerySuggested is the way to go.
From MSDN CommandManager.InvalidateRequerySuggested:
The CommandManager only pays attention to certain conditions in determining when the command target has changed, such as change in keyboard focus. In situations where the CommandManager does not sufficiently determine a change in conditions that cause a command to not be able to execute, InvalidateRequerySuggested can be called to force the CommandManager to raise the RequerySuggested event.
This would explain why the focus changes and keypresses would cause the buttons to enable. The page also shows putting the call in a timer. Because of this, I assume it is not as resource intensive as I thought. So, I guess it's my permanent solution.
I had to make a few changes to get the buttons to enable without focus changes.
The boolean values were being set within a method called from an event thread. I had tried calling CommandManager.InvalidateRequerySuggested along with it, but nothing happened. Eventually I thought it might have something to do with the thread. This is what ended up resolving it.
In the parent form that the tab manager class (containing the event handlers and other logic) has access to, I added an invoke method:
Public Sub InvokeOnUiThread(ByRef uiAction As Action, Optional ByRef doAsync As Boolean = False)
Dim dispatchObject As Dispatcher = orderTicketView.Dispatcher
If (dispatchObject Is Nothing OrElse dispatchObject.CheckAccess()) Then
uiAction()
Else
If doAsync Then
dispatchObject.BeginInvoke(uiAction, DispatcherPriority.Normal)
Else
dispatchObject.Invoke(uiAction, DispatcherPriority.Normal)
End If
End If
End Sub
In the tab manager event handler, I changed it to call the update routine through the invoker:
formOrderTicketView.InvokeOnUiThread(New Action(AddressOf UpdateButtons))
At the bottom of the UpdateButtons method, I added a call to the CommandManager if a change has been made that would require a requery:
CommandManager.InvalidateRequerySuggested()
I do not know what type of performance hit this would have, but apparently WPF executes it in its own way when focus changes and such. Calling it directly is the advised way to force it.
From MSDN CommandManager.InvalidateRequerySuggested:
The CommandManager only pays attention to certain conditions in determining when the command target has changed, such as change in keyboard focus. In situations where the CommandManager does not sufficiently determine a change in conditions that cause a command to not be able to execute, InvalidateRequerySuggested can be called to force the CommandManager to raise the RequerySuggested event.
Since it is working now, I am taking this as the resolution.
The command that's bound to the button...is there a CanExecute delegate with it? If so, you have to raise CanExecuteChanged when that delegate should be re-evaluated. Also, make sure the implementation of CanExecute isn't broken and incorrectly returning false;
I tried to move next cell to edit although there is an validation error. I've used following code.
protected override void OnCellEditEnding(DataGridCellEditEndingEventArgs e)
{
e.Cancel = true;
}
Referred Article - edit wpfdatagrid other cells while one of it's cell is invalid
It works fine, but when I add a background row color to it, the color disappears when editing
There is a different Style for cells that are in edit mode. Because you cancel escaping the edit mode by the code you've shown, this style will always show as soon as you started editing. Keep in mind, that the cells being in edit mode could also cause other problems. It would be better to change the behaviour of your code to only cancel the CellEditEnding-Event when there are validation errors.
To address the issue of the color change: DataGirdColumns have a EditingElementStyle that can be changed. To bind the Background of the EditingElementStyle (in this example of the DataGridTextColumn "Test") to the normal (not editing) Background use the following XAML:
<DataGridTextColumn Header="Test">
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="TextBox">
<Setter Property="Background" Value="{Binding Background}"/>
</Style>
</DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>
Then the background won't change when you edit a cell.
I am fairly new to Xaml.
I am learning UWP(Universal Windows Platform) and I have more buttons and I want to bind their Background property to a property of a ViewModel that will change during some events.
I implemented the INotifyPropertyChanged and everything works ok (the color of the buttons change) when I bind the Background property in the Buttons' declaration in XAML:
<Button Content="0" Grid.Column="0" Grid.Row="5"
Background="{Binding ButtonColor, Source={StaticResource AppViewModel}}" Style="{StaticResource BasicButton}"/>
StaticResource AppViewModel is a resource in App.xaml:
<Application.Resources>
<viewModel:AppViewModel x:Key="AppViewModel" />
</Application.Resources>
I don't know how ok is to declare a ViewModel for App.xaml, but it's a solution I found for having global variables (the variables are held inside the viewModel).
Now back to my question:
As I don't want to bind the Background on every single button, I tried to add it on the style like this:
<Style x:Key="BasicButton" TargetType="Button">
<Setter Property="Background" Value="{Binding ButtonColor, Source={StaticResource AppViewModel}}" />
</Style>
But now when the color variable is changing during running the app, the UI doesn't update anymore.
It seems that binded properties in styles don't respond to changes of variables.
What am I doing wrong?
Thank you for any answers.
After more searching I found a video from Jerry Nixon : http://blog.jerrynixon.com/2013/01/walkthrough-dynamically-skinning-your.html
It seems that because we don't have DynamicResource in uwp / winrt, we have to do a trick:
We renavigate to the same frame. So after we change the property, we have to do something like this:
var frame = Window.Current.Content as Frame;
frame.Navigate(frame.Content.GetType());
frame.GoBack();
It's like invalidating a control in Windows Forms. It's making the UI redraw itself.
I'm not sure if this has side effects, I'll have to dig more. I'll come back if I find any.
I'm using the latest MahApps WPF toolkit and I'm having a bit of trouble with applying my own styles onto its controls, precisely the PasswordBox.
I've defined the styles in a separate .xaml file which is included in the App.xaml file so that it is globally visible, across all .xaml files.
But when I use the style specified under a key the MahApps ClearTextButton refuses to appear on the control.
Here is my style:
<Style x:Key="DefaultPasswordBoxStyle"
TargetType="{x:Type PasswordBox}"
BasedOn="{StaticResource ResourceKey={x:Type PasswordBox}}">
<Setter Property="HorizontalContentAlignment">
<Setter.Value>Center</Setter.Value>
</Setter>
<Setter Property="FontSize">
<Setter.Value>16</Setter.Value>
</Setter>
</Style>
And its usage in a separate .xaml file:
<PasswordBox Margin="{StaticResource ControlMargin}"
controls:TextBoxHelper.ClearTextButton="True"
Style="{StaticResource DefaultPasswordBoxStyle}"
Width="200" />
If I delete the Style attribute the button shows as it is supposed but want to be able to apply my own styles also. It is actually visible in the XAML designer, which is funny. I tried DynamicResource, as well, but with the same results.
So to continue on from the original comments, you had a Type set as your Resource instead of pointing to a Key name. So once you gave your new custom template a proper path to find the original Style template as a BasedOn condition to inherit the rest of the MahApps style then the issue was resolved.
The VS underlining/not locating the resource thing, well I run into that all the time and I'm kind of convinced it's a defect in VS though I wouldn't mind knowing how to clear that off as well. It's annoying since sometimes it will have those errors in the IDE, sometimes it won't, lots of fun.
In the meantime, now that you have your template referencing the correct one as its base with the resource dictionaries referenced properly then all is well in the world again. Hope this helped, cheers!
I am working on a windows phone 7 application that uses the FluidMoveBehavior in some of my ListBoxes. For some reason, the FluidMoveBehavior animation seems to want to activate at inappropriate times. I currently have a ListBox on my main page, and I use the following ItemsPanelTemplate which is just a basic StackPanel with a FluidMoveBehavior attached to it:
<ItemsPanelTemplate x:Key="fancyListBoxItemsPanelTemplate">
<StackPanel>
<Custom:Interaction.Behaviors>
<il:FluidMoveBehavior AppliesTo="Children">
<il:FluidMoveBehavior.EaseX>
<ExponentialEase EasingMode="EaseInOut"/>
</il:FluidMoveBehavior.EaseX>
<il:FluidMoveBehavior.EaseY>
<ExponentialEase EasingMode="EaseInOut"/>
</il:FluidMoveBehavior.EaseY>
</il:FluidMoveBehavior>
</Custom:Interaction.Behaviors>
</StackPanel>
</ItemsPanelTemplate>
This works fine when I add/remove items while on the same screen. The animation plays perfectly. However, when I navigate to a new page from my main page, then navigate back, the fluid move animation is triggered as if all of the items were added at once. Is there any way to disable this behavior so it only triggers the animation when the list actually changes?
this is happening because as you navigate to the page with the list box, the list box is created again, which is similar to adding all the items at once which in tuns fires the fluid move trigger. One possible (may not be the legitimate) solution is to have two identical ItemPanel template, one with the behavior and the other without it. When you first navigate to the page apply the template w/o the behavior. Later replace it with the one with the behavior.
Hope that helps.