|
I use code-behind to load images; that works.
I also hook up the "ImageFailed" event; then you know why it's not working (somewhat).
(MVVM has too much "indirection" for my brain).
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
Quote: DisplayView.xaml
<Page.DataContext>
<vm:DisplayViewModel/>
</Page.DataContext>
...
<Image x:Name="imgDisplayView" Source="{Binding ImagePath}">
<Image.RenderTransform>
<TransformGroup>
<TranslateTransform/>
<RotateTransform/>
<ScaleTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
... The problem is that your DisplayPanelView is setting its DataContext to a new instance of your viewmodel. The image path you set on the DataContext of the DisplayControlView will have no effect on the property of the separate viewmodel instance used as the DataContext for DisplayPanelView .
You need both controls to use the same viewmodel instance for their DataContext . Depending on how your ReviewView viewmodel is set up, you probably want to expose a single DisplayViewModel instance as a property on that viewmodel, and have both Display... views bound to that.
For example:
public class ReviewViewModel : ViewModelBase
{
private DisplayViewModel _display = new DisplayViewModel();
public DisplayViewModel
{
get { return _display; }
set { SetValue(ref _display, value); }
}
} ReviewView.xaml:
<views:DisplayControlView DataContext="{Binding Path=DisplayViewModel}" />
<views:DisplayPanelView DataContext="{Binding Path=DisplayPanelView}" /> Remove the <Page.DataContext> from both DisplayControlView and DisplayPanelView pages.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Here is something can't run properly. Is below code is written in NEW class called ReviewViewModel?
public class ReviewViewModel : ViewModelBase
{
private DisplayViewModel _display = new DisplayViewModel();
public DisplayViewModel
{
get { return _display; }
set { SetValue(ref _display, value); }
}
}
But the Intellisense will show warning about the declaration of DisplayViewModel and the function of SetValue is invalid....
What prerequisites are needed for this code?
Sincere thank Richard Master to point me!!
All Views need one ViewModel instance, and I had no idea about how to set one ViewModel instance until this post point me.
And thank Gerry join this discussion.
modified 21-Jun-21 21:36pm.
|
|
|
|
|
In addition:
ReviewView.xaml
<Page.DataContext>
<vm:DisplayViewModel/>
</Page.DataContext>
<Grid Background="{DynamicResource ThirdHueLightBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="280"/>
<ColumnDefinition MinWidth="690"/>
</Grid.ColumnDefinitions>
<Frame Grid.Column="0" Source="Frame/DisplayControlView.xaml"/>
<Frame Grid.Column="1" Source="Frame/DisplayPanelView.xaml"/>
</Grid>
|
|
|
|
|
One thing I see right off the bat is that when you use DataContext you are instantiating DisplayViewModel.
<Page.DataContext>
<vm:DisplayViewModel/>
</Page.DataContext>
You basically created two instances of DisplayViewModel.
One fix would be to instantiate it somewhere else in C# :
DisplayViewModel displayViewModel = new DisplayViewModel();
Then add to each page then for each page in C# on initialization add:
this.DataContext = ????.displayViewModel
Now they will both point to the same instance.
So many years of programming I have forgotten more languages than I know.
|
|
|
|
|
Thank for point me.
Actually, I had solved this problem a few moment ago... XD
Here is my solution:
1. Using singleton-pattern to fix one execution instance
2. At each View code-behind(???.xmal.cs) which needs to using the same ViewModel, I add below code
this.context = viewmodel.instance
BTW, I also ask in below Taiwan IT forum......and self-question at below to show my detail solution XD
[問題] MVVM架構下,如何多個View共用同一個ViewModel變數 - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天[^]
For you reference~~~
Thanks guys again
modified 13-Oct-21 22:12pm.
|
|
|
|
|
I have also seen static's used. Not a "static" fan but it works. Static's have there place. The reason Serilog is so easy to use and hence popular is because of static's.
So many years of programming I have forgotten more languages than I know.
|
|
|
|
|
I have a simple login window with Company, User Name, and Password. There is a Remember Me checkbox, and if the user checks it, then I pre-fill in the Company and User Name the next time they run the app. In that case, I want to set focus to the Password field.
In the Window's XAML I have
FocusManager.FocusedElement="{Binding FocusedElementName}"
Then in the VM I set the FocusedElementName property to either "company" or "password."
The problem is that the focus is not being set. The code behind is working as expected.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
The problem is that you're setting the Path of the binding. The FocusedElement property relies on the ElementName of the binding:
FocusManager.FocusedElement="{Binding ElementName=firstButton}" You can't bind the properties of a binding, so you can't do this:
{Binding ElementName={Binding ...}} Short of using the code-behind for the view, the simplest option is probably to use a style with a series of data triggers, as shown in this SO answer[^]:
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding FocusedElement}" Value="First">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=txtbox1}"/>
</DataTrigger>
</Style.Triggers>
</Style>
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I have a style FooStyle with some properties and an animation.
I have two other styles Bar1Style and Bar2Style which is based on the FooStyle and sets some properties. I would like to alter the the values in the animation for the Bar-styles.
In the animation I'm altering the buttons ScaleX and ScaleY values with the MouseIsOver trigger.
In the code bellow you notice the values FrameOneValue and FrameTwoValue .
<Style TargetType="Button" x:Key="FooStyle">
<Style.Resources>
<system:Double x:Key="FrameOneValue">1.0</system:Double>
<system:Double x:Key="FrameTwoValue">1.05</system:Double>
</Style.Resources>
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="RenderTransformOrigin" Value="0.5 0.5" />
<Setter Property="RenderTransform">
<Setter.Value>
<TransformGroup>
<ScaleTransform/>
</TransformGroup>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="{DynamicResource FrameOneValue}"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="{DynamicResource FrameTwoValue}"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="{DynamicResource FrameOneValue}"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="{DynamicResource FrameTwoValue}"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="{DynamicResource FrameTwoValue}"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="{DynamicResource FrameOneValue}"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="{DynamicResource FrameTwoValue}"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="{DynamicResource FrameOneValue}"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style> In the Bar1Style and Bar2Style styles I would like to alter the values for FrameOneValue and FrameTwoValue to suit these styles. As the XAML-code to setup for the animation is quite large I would like to have have the definition in the FooStyle .
The Bar1Style and Bar2Style might look like this:
<Style TargetType="{x:Type Button}" x:Key="Bar1Style" BasedOn="{StaticResource FooStyle}">
<Style.Resources>
<system:Double x:Key="FrameOneValue">2.0</system:Double>
<system:Double x:Key="FrameTwoValue">2.05</system:Double>
</Style.Resources>
<Setter Property="Background" Value="Blue" />
</Style>
<Style TargetType="{x:Type Button}" x:Key="Bar2Style" BasedOn="{StaticResource FooStyle}">
<Style.Resources>
<system:Double x:Key="FrameOneValue">3.0</system:Double>
<system:Double x:Key="FrameTwoValue">3.05</system:Double>
</Style.Resources>
<Setter Property="Background" Value="Red" />
</Style> I would then use this like:
<Window x:Class="Main.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Main"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel Orientation="Vertical">
<Button Content="btn1" Style="{DynamicResource FooStyle}" />
<Button Content="btn2" Style="{DynamicResource Bar1Style}" />
<Button Content="btn2" Style="{DynamicResource Bar2Style}" />
</StackPanel>
</Window> But this fails hard due to:
Cannot freeze this Storyboard timeline tree for use across threads Which seems to be due to I have specified DynamicResource in the FooStyle .
Which means that I cannot specify values for an animation dynamically in the Bar1Style and Bar2Style styles
Is there some way to solve this?
It's very annoying to have an entire setup of the animation for each style. I just want to alter the values in the Bar-style.
|
|
|
|
|
I'd create a new button "user control" that accepts 2 storyboard values and be done with it.
Bind to public properties added to the UC.
Creating & using a UserControl - The complete WPF tutorial
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
modified 20-May-21 15:20pm.
|
|
|
|
|
I'm working on implementing security into my application. When a user logs in a User instance is returned, and on that is a List<string> property of right, which looks like this:
List _userRights = new List
{
"can_add_employees",
"can_edit_employees",
};
The tags in the list are stored in a table. If the tag is returned, then the user has access. If it's not returned, then the user does not have acccess. The Security piece is already done.
Now, I want to implement it in XAML. Richard Deeming gave me some direction on this a while back and I've built on his idea. I now have this Behavior class: (thanks Richard)
public static class SecurityBehavior
{
private static readonly char[] TagSeparators = { '|' };
#region Allow Enable
public static readonly DependencyProperty AllowEnableProperty =
DependencyProperty.RegisterAttached("AllowEnable",
typeof(bool),
typeof(SecurityBehavior),
new PropertyMetadata(false, OnSecurityChanged));
public static bool GetAllowEnable(DependencyObject obj)
{
return (bool)obj.GetValue(AllowEnableProperty);
}
public static void SetAllowEnable(DependencyObject obj, bool value)
{
obj.SetValue(AllowEnableProperty, value);
}
#endregion
#region Security Tags
public static readonly DependencyProperty SecurityTagsProperty =
DependencyProperty.RegisterAttached("SecurityTags",
typeof(string), typeof(SecurityBehavior),
new PropertyMetadata("", OnSecurityChanged));
public static string GetSecurityTags(DependencyObject obj)
{
return (string)obj.GetValue(SecurityTagsProperty);
}
public static void SetSecurityTags(DependencyObject obj, string value)
{
obj.SetValue(SecurityTagsProperty, value);
}
private static void OnSecurityChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
bool canEnable = GetAllowEnable(sender);
if (canEnable)
{
string[] tags = GetSecurityTags(sender).Split(TagSeparators, StringSplitOptions.RemoveEmptyEntries);
foreach (string tag in tags)
{
canEnable &= SecurityService.HasRights(tag);
}
}
var element = (UIElement)sender;
element.IsEnabled = canEnable;
}
#endregion
}
Notice that it calls a static SecurityService class:
public static class SecurityService
{
private static List<string> _userRights;
public static bool HasRights(string right)
{
return _userRights.Contains(right);
}
static SecurityService()
{
_userRights = new List
{
"can_add_employees",
"can_edit_employees",
};
}
}
I then use it like this in XAML:
<TextBox Grid.Row="0"
Grid.Column="1"
Text="{Binding EmployeeName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
local:SecurityBehavior.AllowEnable="{Binding AreFieldsEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
local:SecurityBehavior.SecurityTags="can_add_employees|can_edit_employees"/>
"AreFieldsEnabled" is a bool property on the base ViewModel that is set to true when the view is in either Add or Edit mode.
This works, there are a couple of issues I'm stuck on.
- This approach requires that I have the tags listed in the XAML. I can then add or remove tags to any specific UI element as needed, but it requires going back into the XAML to do so. I was considering setting the element's Name and have the service look it up and determine if it can be enabled.
- In some cases there are addition factors that determine if/when a UI element should be enabled, such as another checkbox beging checked, or a specific combox box item being selected somewhere else.
I'd like to hear suggestions.
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I have two style FooStyle and BarStyle .
I also have three TextBlocks and two of them use the styles above.
In the FooStyle I have specified a double (the Wid parameter) that is used to set the Width of the TextBlock (txt2) to 20.
In the BarStyle I would like to use the FooStyle but override the Wid parameter with the value 40 on the TextBlock (txt3).
But the txt3 TextBlock's Width don't get a longer Width. It still has the same Width as txt2.
Here is my code
<Window x:Class="Main.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Window.Resources>
<Style x:Key="FooStyle" TargetType="TextBlock">
<Style.Resources>
<sys:Double x:Key="Wid">20</sys:Double>
</Style.Resources>
<Setter Property="Width" Value="{StaticResource Wid}" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style x:Key="BarStyle" TargetType="TextBlock" BasedOn="{StaticResource FooStyle}">
<Style.Resources>
<sys:Double x:Key="Wid">40</sys:Double>
</Style.Resources>
</Style>
</Window.Resources>
<StackPanel Orientation="Vertical">
<TextBlock Text="txt1" Background="red" Width="100" />
<TextBlock Text="txt2" Background="Lime" Style="{StaticResource FooStyle}" />
<TextBlock Text="txt3" Background="Blue" Style="{StaticResource BarStyle}" />
</StackPanel>
</Window> Is it possible to overwrite the Wid parameter in the BarStyle?
|
|
|
|
|
You've assigned the width using a StaticResource . If you want it to change based on the resources of the "derived" style, use DynamicResource instead.
<Setter Property="Width" Value="{DynamicResource Wid}" /> You can then override the value with the resources of a "derived" style:
<Style x:Key="BarStyle" TargetType="TextBlock" BasedOn="{StaticResource FooStyle}">
<Style.Resources>
<sys:Double x:Key="Wid">40</sys:Double>
</Style.Resources>
</Style> Or directly on the control:
<TextBox Text="txt4" Background="Purple" Style="{StaticResource FooStyle}">
<Style.Resources>
<sys:Double x:Key="Wid">80</sys:Double>
</Style.Resources>
</TextBox>
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thank you!
I got it to work in my example application.
But in my real application fail hard. I'll make a new post about it.
|
|
|
|
|
I have a construction management app that is used to manage house framing. The client now want to use it to manage finish work, such as doors and cabinets, etc. The structure of the data is very similar - almost identical, and functionally the app would work the same with a few one-off views for each. My thought is that when the user logs in, they would now also pick which company they want to work in.
The question is this... There are going to be some TextBlocks that will need to be changed depending on what company the user is in. For example, the word "Project" might need to say "Task" depending on the company.
One idea I'm tossing around is to store these words in a resources file, something like:
<data name="a_project_caption" xml:space="preserve">
<value>Project</value>
</data>
<data name="b_project_caption" xml:space="preserve">
<value>Task</value>
</data>
Next, in the XAML I would have something like a behavior maybe?:
<TextBlock Tag="project_caption" beh:ResolveCaption/>
The behavior takes the value in the Tag and sets the textblock's text based on what it finds in the resource file, and throws if it can't resolve it.
I'm open to suggestions on this.
Thanks!
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 14-May-21 16:58pm.
|
|
|
|
|
I know absolutely zilch about your environment, but your question reminds me of something else which should already have been solved by someone else.
I18N - Internationalisation.
Company 1 <=> English
Company 2 <=> French
...
Cheers,
Peter
Software rusts. Simon Stephenson, ca 1994. So does this signature. me, 2012
|
|
|
|
|
Not really. I've done internalization, and in that case you create a resource file for each language, then ship the resource file you need.
This has nothing to do with language. In this case, there is will only be one resource file, and the captions for the textblocks are ALL in it, and it's only the selection of the company that decides which gets used.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I'd store these values in something like a database and populate it accordingly.
|
|
|
|
|
Whenever I needed to do this I always used the control name, not the tag - it is so useful for other things. The data was always stored in a table possibly with other customisation of each form. You know they are going to vary more than labels between entities.
For major variations I would create a new form and deal with it in the navigation.
Never underestimate the power of human stupidity -
RAH
I'm old. I know stuff - JSOP
|
|
|
|
|
In the Loaded event of the Label, I'd look up the current caption in the app's current "translation" dictionary, and substitute whatever words were found.
I've been transliterating that way: text with "old" words that get substituted with new words for given author. I sometimes hop twice and do a final IPA (pronunciation) translation.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
Here's an example of handling data beign pasted into a textbox:
Masking input to a WPF TextBox | Atomic Blography
In the XAML he wires up the Pasting hander like this:
<TextBox PreviewTextInput="PreviewTextInputHandler"
DataObject.Pasting="PastingHandler" />
I would like to handle all of this in a TextBox override class. I can easily bring in the preview handler part, but how would you wire up the DataObject.Pasting="PastingHandler" from within the base class? His code is doing in the XAML where the TextBox is defined.
I want to encapsulate all of this in my TextBox class, but there's no override, and the DataObject.Pasting event is set to read only so you can't hook to the event.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
|
That did it. Thanks!
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I have a nullable decimal TaxRate property on an entity. I want to format/style the textbox to enter a percentage. What I have so far doesn't work. If I start out by entering a decimal point, then it works fine.
If I start out by entering a digit, then I cannot enter a decimal.
<Style x:Key="percentageStyle"
TargetType="{x:Type TextBox}"
BasedOn="{StaticResource textBoxStyle}">
<pre>
<Setter Property="Text" Value="{Binding SelectedStatesCountiesCities.TaxRate, StringFormat={}{0:N2}%}" />
<Style.Triggers>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="Text" Value="{Binding SelectedStatesCountiesCities.TaxRate}" />
</Trigger>
</Style.Triggers>
<TextBox Grid.Row="1"
Grid.Column="2"
Text="{Binding SelectedStatesCountiesCities.TaxRate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource percentageStyle}"
HorizontalAlignment="Left"
IsEnabled="True"
Width="100"/>
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|