Using custom XML namespaces to reference external DLLs in Kaxaml - wpf

I can get Kaxaml to load external assemblies using CLR-namespaces, that however is a pain because one needs a lot of mappings to target all the different namespaces in an assembly while the custom XmlnsDefinition on the assembly would allow one to get away with just one or a few.
When looking for a solution i obviously found this question but it only seems to cover the use of CLR-namespaces as none of the answers seemed to work for custom namespaces ("Cannot set unknown member ...").
Example:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:is="http://schemas.microsoft.com/expression/2010/interactions">
<!-- ... -->
<Button Content="Test">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<is:ChangePropertyAction PropertyName="IsOpen"
TargetName="popup"
Value="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
This will not work, however if you use CLRs it does:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:is="clr-namespace:Microsoft.Expression.Interactions;assembly=Microsoft.Expression.Interactions"
xmlns:isc="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions">
<!-- ... -->
<Button Content="Test">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<isc:ChangePropertyAction PropertyName="IsOpen"
TargetName="popup"
Value="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
The is namespace is not used here and i had to add a sub-namespace of the interactions assembly.
It would be ideal if the first method could be made to work.

So while typing this question i stumbled upon one way to use the custom namespaces: You have to make Kaxaml load the assembly at least once.
This can be done using some dummy object which references a CLR-namespace within the referenced assembly. If parsed once this loader can be discarded, of course this needs to be done every time Kaxaml is run.
e.g.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:is="http://schemas.microsoft.com/expression/2010/interactions">
<Page.Resources>
<FrameworkElement x:Key="loader"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:is="clr-namespace:Microsoft.Expression.Interactions;assembly=Microsoft.Expression.Interactions" />
</Page.Resources>
Using snippets or the default file this can be made comparatively convenient while still not ideal so if someone knows a good fix please let me know.

Related

Only last icon in XAML shown when icon used from resources

when I try to use a material design icon from the icon pack that is defined in the ResourceDictionary, only the first icon in XAML is rendered at run time. I've followed an example that can be found here.
Example follows:
App.xaml:
<Application x:Class="TestWpf.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestWpf"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary Source="pack://application:,,,/TestWpf;component/Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Dictionary1.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes">
<materialDesign:PackIcon x:Key="CashIcon" Kind="Cash" />
</ResourceDictionary>
MainWindow.xaml:
<Window x:Class="TestWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<Button Content="{DynamicResource CashIcon}" />
<Button Content="{DynamicResource CashIcon}" />
<Button Content="{DynamicResource CashIcon}" />
</StackPanel>
</Window>
And the result is a window that looks like this:
In xaml editor all buttons have icons on them, as expected:
Why is this happening and, more important, how to fix this?
P.S. We've found out that if you create two Cash icons in the ResourceDictionary and apply each to a button, then they will both be shown but again, only once, you can't have say 3 buttons and 2 icons in ResourceDictionary.
one more solution is to use a non-shared resource (x:Shared Microsoft docs)
<materialDesign:PackIcon x:Key="CashIcon" Kind="Cash" x:Shared="False"/>
x:Shared Attribute: When set to false, modifies WPF resource-retrieval behavior so that requests for the attributed resource create a new instance for each request instead of sharing the same instance for all requests.
A scenario for x:Shared="false" is if you define a FrameworkElement or FrameworkContentElement derived class as a resource and then you introduce the element resource into a content model. x:Shared="false" enables an element resource to be introduced multiple times in the same collection (such as a UIElementCollection). Without x:Shared="false" this is invalid because the collection enforces uniqueness of its contents. However, the x:Shared="false" behavior creates another identical instance of the resource instead of returning the same instance.
The PackIcon type is a Control. An element in the visual tree in WPF can only have a single parent. In other words, the pack icon is still a single instance added as child of the first button, then moved to the second, then to the third. You will in fact have to create multiple instances of the pack icon.
Instead of creating resources, you could use the PackIcon markup extension.
<StackPanel>
<Button Content="{materialDesign:PackIcon Cash}"/>
<Button Content="{materialDesign:PackIcon Cash}"/>
<Button Content="{materialDesign:PackIcon Cash}"/>
</StackPanel>
Depending on your actual scenario, you could alternatively create a DataTemplate, which will automatically create instances of the pack icons for each button.
<DataTemplate x:Key="CashPackIconTemplate">
<materialDesign:PackIcon Kind="Cash" />
</DataTemplate>
<StackPanel>
<Button ContentTemplate="{StaticResource CashPackIconTemplate}"/>
<Button ContentTemplate="{StaticResource CashPackIconTemplate}"/>
<Button ContentTemplate="{StaticResource CashPackIconTemplate}"/>
</StackPanel>

Disable Triggers in Design Time

Im developing a WPF Application with a TabControl. Inside the TabItems of this TabControl I have implemented EventTriggers which react on a LeftButtonMouseDownEvent to do some stuff. My Problem is that during Design Time of Visual Studio the Event is triggered and it seems to block any further interactions in the Design Window.
Is there a possibility to ignore the trigger, when my Visual Studio is in Design Time. I would prefer to do this in pure XAML. I know that there exists the "mc:Ignorable" tag, but I want it the other way round. If needed i posted a Code Snippet for you.
Thanks for your help!
<TabItem>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<SomeAction/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TabItem>
I don't know how to do it in xaml, but, may be, adding to code SomeAction this, will resolve your problem.
var isInDesignMode = DesignerProperties.GetIsInDesignMode(new DependencyObject());
if(isInDesignMode)
{
// using in VisualStudio or Blend
}
else
{
// using in application
}
Try extending mc:Ignorable with i for your case, i.e. mc:Ignorable="d i":
<UserControl ...
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
...
d:DesignHeight="600"
d:DesignWidth="800"
...
mc:Ignorable="d i">
...
<TabItem>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<SomeAction/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TabItem>
...
</UserControl>

Can UserControl.Resources reference a different assembly than the control's contents?

I'm having a bizarre problem with one of my UserControls where if I only make use of a xml namespace in the UserControl.Resources the assembly isn't found. But if I also make use of the same xml namespace in the contents of the control then both work properly.
<UserControl x:Class="MyControl"
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:myAssemblyAlias="clr-namespace:MyAssembly;assembly=MyAssembly">
<UserControl.Resources>
<ControlTemplate x:Key="AControlTemplate">
<... other stuff .../>
<myAssemblyAlias:MyObject/>
</ControlTemplate>
</UserControl.Resources>
<Grid>
<myAssemblyAlias:MyObject x:Name="MyObjectInContent" />
</Grid>
</UserControl>
If both instances of MyObject are present it works correctly. If I comment out the line for MyObjectInContent I get a runtime error telling me MyAssembly can't be found.
Anyone ever seen anything like this before? It almost seems like Visual Studio has the reference available properly at compilation but not at runtime.

How to see design-time data-binding in XAML editor (it works in runtime)?

I data-binded version number to appear as follows:
<Window <!-- ... --> DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<TextBlock>
Version is:
<Run Text="{Binding Version, Mode=OneWay}"></Run>
and advancing...
</TextBlock>
</Grid>
</Window>
and it's working during run-time.
How can I see it during design-time in the XAML editor in Visual Studio 2012 ? I only see:
Version is: and advancing...
instead of:
Version is: 5.2.2 and advancing...
EDIT - My solution:
Jure's answer below works, but I ended up using a dummy view-model static code technique, which works better for me since the data is a mock of the real view-model type:
d:DataContext="{Binding Source={StaticResource DesignViewModel}}" ...
Make sure that you have these definitions at the root tag of your xaml file (in your case the Window tag):
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Then, anywhere in the xaml (including the root tag) you can add this:
d:DataContext="{d:DesignInstance myNamespace:MyViewModel, IsDesignTimeCreatable=True}"
Now you just need to make sure that you initialize the values in a constructor or have default values for properties.
If you need to run a special logic for design mode, look at this answer.
Short answer, you can't do it that way. VS designer is not executing runtime code and your binding will not be resolved in design time.
But there is support for design time data through d:DesignData extension.
You can set design data context this way:
<Window xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DataContext="{d:DesignData Source=/SampleData/SomeSampleData.xaml}"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<TextBlock>
Version is:
<Run Text="{Binding Version, Mode=OneWay}"></Run>
and advancing...
</TextBlock>
</Grid>
d:DataContext={d:DesignData.... sets the desing time DataContext that will be used to resolve bindings in VS designer surface. You can set it to a xaml file that contains your sample data. Sample xaml file should be built with "DesignData" build action.
See more here: http://blogs.msdn.com/b/wpfsldesigner/archive/2010/06/30/sample-data-in-the-wpf-and-silverlight-designer.aspx

WPF/Silverlight States - Activate from XAML?

Kind of a quick question:
Is it possible to activate a viewstate from XAML? I have been only able to activate one from CS, using the VisualStateManager.GotoState() method. This would fix some of my MVVM issues if it were easily possible.
Thanks
If you are familiar with Blend behaviors, triggers, and actions there is a GoToStateAction which is a part of the Microsoft.Expression.Interactivity.Core namespace. You will have to reference the interactivity assemblies which are part of the Blend SDK.
Once you have the references set up it's as easy as specifying the GoToStateAction to react to some sort of trigger... all in XAML. Here is an example which fires the action off of the Loaded event using an EventTrigger:
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions">
<Grid x:Name="LayoutRoot">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<ic:GoToStateAction StateName="MyVisualState"/>
</i:EventTrigger>
</i:Interaction.Triggers>
...
</Grid>
</UserControl>
More info and tutorial about the specific GoToState action here.
EDIT: This answer is specific to Silverlight, not sure if this is available in WPF.

Resources