How to get base uri of referencing XAML in a custom control - wpf

I have an custom control, which has an Image element with its Source property exposed to user, like this:
<ControlTemplate>
<Image x:Name="PART_Image" Source="{Binding ImageUri, RelativeSource={RelativeSource TemplatedParent}}"/>
</ControlTemplate>
where ImageUri is an property in the control class, like this:
public Uri ImageUri { get; set; }
This custom control is in an assembly customcontrol.dll, I can reference and use this control in an .exe with no problem, like this:
<cc:MyControl ImageUri="/Resources/Image.png" />
where Image.png is a resource of the .exe project.
But if I reference and use this control in an dll assembly, there is a problem, I have to use a absolute "pack://..." uri to reference an image in the calling dll, if I use an relative uri like "Resources/Image.png", the resource cant be loaded, it turns out, when this uri is applied on the Image element, it resolves the relative uri from customcontrol.dll, not the calling dll assembly, so I want to do this:
public Uri ImageUri {
get { ...... }
set {
if (!value.IsAbsolute) {
// Get the assembly name of parent xaml file or code
// and construct a "pack://" uri from the assembly name
// and value.OriginalString, but how ??????
}
}
}
How can I get the assembly of the XAML code that uses my custom control?
If the control is used in code maybe I can use GetCallingAssembly in my methods, but XAML stuff is called from PresontationCore.dll, how can I find out the XAML assembly???

OK I have found a solution myself. I should implement IUriContext interface,
which has only one property: Uri BaseUri, this is exactly what I want.

Related

How can add hint from settings in wpf material desgin [duplicate]

In WPF, Can I use binding with values defined in Settings? If this is possible, please provide a sample.
First, you need to add a custom XML namespace that will design the namespace where the settings are defined:
xmlns:properties="clr-namespace:TestSettings.Properties"
Then, in your XAML file, access the default settings instance using the following syntax:
{x:Static properties:Settings.Default}
So here is the final result code:
<ListBox x:Name="lb"
ItemsSource="{Binding Source={x:Static properties:Settings.Default},
Path=Names}" />
Source: WPF - How to bind a control to a property defined in the Settings?
Note: As pointed out by #Daniel and #nabulke, don't forget to set Access Modifier of your settings file to Public and Scope to User
The solution above does work, but I find it quite verbose... you could use a custom markup extension instead, that could be used like this :
<ListBox x:Name="lb" ItemsSource="{my:SettingBinding Names}" />
Here is the code for this extension :
public class SettingBindingExtension : Binding
{
public SettingBindingExtension()
{
Initialize();
}
public SettingBindingExtension(string path)
:base(path)
{
Initialize();
}
private void Initialize()
{
this.Source = WpfApplication1.Properties.Settings.Default;
this.Mode = BindingMode.TwoWay;
}
}
More details here : http://www.thomaslevesque.com/2008/11/18/wpf-binding-to-application-settings-using-a-markup-extension/
#CSharper's answer did not work for my WPF application coded in VB.NET (not C#, unlike apparently 99.999% of other WPF applications), as I got a persistent compiler error complaining that Settings could not be found in the MyApp.Properties namespace, which would not go away even after rebuilding.
What worked instead for me, after much searching online, was to instead use the local XAML namespace created by default in my application's main window XAML file:
<Window
<!-- Snip -->
xmlns:local="clr-namespace:MyApp"
<!-- Snip -->
><!-- Snip --></Window>
...and bind to my settings through it using something like the following (where MyBooleanSetting is a setting I defined in my project properties of type Boolean and scope User, with the default Friend access modifier):
<CheckBox IsChecked="{Binding Source={x:Static local:MySettings.Default}, Path=MyBooleanSetting, Mode=TwoWay}"
Content="This is a bound CheckBox."/>
To ensure the settings are actually saved, be sure to call
MySettings.Default.Save()
...somewhere in your code-behind (such as in the Me.Closing event for your MainWindow.xaml.vb file).
(Credit to this Visual Studio forum post for the inspiration; see the reply by Muhammad Siddiqi.)
Here's how I bind the UserSettings:
Generate a dependency variable by typing propdp and then tab twice.
public UserSettings userSettings
{
get { return (UserSettings)GetValue(userSettingsProperty); }
set { SetValue(userSettingsProperty, value); }
}
public static readonly DependencyProperty userSettingsProperty =
DependencyProperty.Register("userSettings", typeof(UserSettings), typeof(MainWindow), new PropertyMetadata(UserSettings.Default));
Now, you can bind userSettings by:
Value="{Binding userSettings.SomeUserSettingHere, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
And make sure you save UserSettings when you change them or on Exit by:
UserSettings.Default.Save();

Using Bitmap Class in XAML [duplicate]

I have two .png files added to my resources which I need to access their Uri when doing binding.
My xaml code is as followed:
<Grid>
<Image>
<Image.Source>
<BitmapImage DecodePixelWidth="10" UriSource="{Binding Path=ImagePath}"/>
</Image.Source>
</Image>
</Grid>
and the binding code using ImagePath is:
ImagePath = resultInBinary.StartsWith("1") ? Properties.Resources.LedGreen : Properties.Resources.ledRed;
However
Properties.Resources.LedGreen
returns a Bitmap instead of String containing the Uri of that particular image.
I just want to know how to extract that value without a need to address a path of the image in the directory that it's stored. (Which honestly I am not sure is a right thing to do as I couldn't find any similar situation on the net).
Please let me know if there is even a preferred method to the one I am trying to use if available.
In a WPF application you would usually not store images in Properties/Resources.resx and access them by means of the Properties.Resources class.
Instead you just add the image files to your Visual Studio project as regular files, perhaps in a folder named "Images" or the like. Then you would set their Build Action to Resource, which is done in the Properties window. You get there e.g. by right-clicking the image file and select the Properties menu item. Note that the default value of the Build Action should be Resource for image files anyways.
In order to access these image resources from code you would then use a Pack URI. With the above folder name "Images" and an image file named "LedGreen.png", creating such an URI would look like this:
var uri = new Uri("pack://application:,,,/Images/LedGreen.png");
So you could perhaps declare your property to be of type Uri:
public Uri ImageUri { get; set; } // omitted INotifyPropertyChanged implementation
and set it like this:
ImageUri = resultInBinary.StartsWith("1")
? new Uri("pack://application:,,,/Images/LedGreen.png")
: new Uri("pack://application:,,,/Images/LedRed.png");
Finally your XAML should look like shown below, which relies on built-in type conversion from Uri to ImageSource:
<Grid>
<Image Width="10" Source="{Binding Path=ImageUri}" />
</Grid>
Declare the Properties.Resources.LedGreen property as ImageSource and set it to Uri location rather than the Bitmap object.
Or if you insist of storing it as a bitmap you can get the source by returning Properties.Resources.LedGreen.ImageSource which will be of type ImageSource.
I would prefer the first approach.

How to set ImageSource in a codebehindfile

I have in a UserControl the Property ImageSource. How can I set the ImageSource in my code behind to a Image in my Resources directory?
I want to bind the Image Source to the property ImageSource.
<Image Source="{Binding Path=ImageSource}" />
In order to create a BitmapImage (which is derived from ImageSource) from a resource file in code, you would do the following, provided that the file MyImage.jpg is in a folder named Images of your Visual Studio project, and that its Build Action is set to Resource:
var uri = new Uri("pack://application:,,,/Images/MyImage.jpg");
ImageSource = new BitmapImage(uri); // set the ImageSource property
See also this answer.
You could also directly use the image resource without binding:
<Image Source="/Images/MyImage.jpg" />

binding an image source in XAML

I am trying to bind an image source to my XAML through c#
this works
<Image Source="images/man.jpg"></Image>
this does not work
<Image Source="images/{Binding imagesource}"></Image>
where imagesource is a string variable in the c# file of this xaml and is being set equal to "man.jpg"
here is a way how to do it in XAML:
add this to the namespace:
xmlns:System="clr-namespace:System;assembly=mscorlib"
then add your images paths
<System:String x:Key="ImageRefresh">/Theme;component/Images/icon_refresh.png</System:String>
<System:String x:Key="ImageSearch">/Theme;component/Images/icon_search.png</System:String>
This is how you use it
<Image Height="16" Source="{StaticResource ImageSearch}" Stretch="Uniform" Width="16"/>
This works ok, but if you load your xaml style in Blend it will go bogus..
An object of type "System.String" cannot be applied to a property that expects the type "System.Windows.Media.ImageSource".
I haven't figured out yet, how to replace System:String with that Media.ImageSource... but hey.. it works for me in Visual Studio.
You can't stick a binding mid-way through the value like that. It's either a binding, or it's not. Assuming imagesource is publicly accessible via your DataContext, you could do this:
<Image Source="{Binding imagesource}"/>
However, if it's been set to "man.jpg" then it won't find the image. Either set imagesource to the full path ("images/man.jpg") or use a converter:
<Image Source="{Binding imagesource, Converter={StaticResource RelativePathConverter}}"/>
The converter would prepend "images/" onto its value. However, it may be necessary for the converter to return an ImageSource rather than a string.
Images have bitten me in the past. There is a certain lookup order involved.
When you use "image/man.jpg" it could refer to a file inside your silverlight xap, or relative to the location of XAP file. For example, it could be in YourProject.Web/ClientBin/image/man.jpg.
You should troubleshoot by using full URLs first and find out if this works.
imagesource needs to be an actual Image object, not a string.
Here is a method that will create a new Image object given a path:
public BitmapImage Load(string path)
{
var uri = new Uri(path);
return new BitmapImage(uri);
}

Bind to a value defined in the Settings

In WPF, Can I use binding with values defined in Settings? If this is possible, please provide a sample.
First, you need to add a custom XML namespace that will design the namespace where the settings are defined:
xmlns:properties="clr-namespace:TestSettings.Properties"
Then, in your XAML file, access the default settings instance using the following syntax:
{x:Static properties:Settings.Default}
So here is the final result code:
<ListBox x:Name="lb"
ItemsSource="{Binding Source={x:Static properties:Settings.Default},
Path=Names}" />
Source: WPF - How to bind a control to a property defined in the Settings?
Note: As pointed out by #Daniel and #nabulke, don't forget to set Access Modifier of your settings file to Public and Scope to User
The solution above does work, but I find it quite verbose... you could use a custom markup extension instead, that could be used like this :
<ListBox x:Name="lb" ItemsSource="{my:SettingBinding Names}" />
Here is the code for this extension :
public class SettingBindingExtension : Binding
{
public SettingBindingExtension()
{
Initialize();
}
public SettingBindingExtension(string path)
:base(path)
{
Initialize();
}
private void Initialize()
{
this.Source = WpfApplication1.Properties.Settings.Default;
this.Mode = BindingMode.TwoWay;
}
}
More details here : http://www.thomaslevesque.com/2008/11/18/wpf-binding-to-application-settings-using-a-markup-extension/
#CSharper's answer did not work for my WPF application coded in VB.NET (not C#, unlike apparently 99.999% of other WPF applications), as I got a persistent compiler error complaining that Settings could not be found in the MyApp.Properties namespace, which would not go away even after rebuilding.
What worked instead for me, after much searching online, was to instead use the local XAML namespace created by default in my application's main window XAML file:
<Window
<!-- Snip -->
xmlns:local="clr-namespace:MyApp"
<!-- Snip -->
><!-- Snip --></Window>
...and bind to my settings through it using something like the following (where MyBooleanSetting is a setting I defined in my project properties of type Boolean and scope User, with the default Friend access modifier):
<CheckBox IsChecked="{Binding Source={x:Static local:MySettings.Default}, Path=MyBooleanSetting, Mode=TwoWay}"
Content="This is a bound CheckBox."/>
To ensure the settings are actually saved, be sure to call
MySettings.Default.Save()
...somewhere in your code-behind (such as in the Me.Closing event for your MainWindow.xaml.vb file).
(Credit to this Visual Studio forum post for the inspiration; see the reply by Muhammad Siddiqi.)
Here's how I bind the UserSettings:
Generate a dependency variable by typing propdp and then tab twice.
public UserSettings userSettings
{
get { return (UserSettings)GetValue(userSettingsProperty); }
set { SetValue(userSettingsProperty, value); }
}
public static readonly DependencyProperty userSettingsProperty =
DependencyProperty.Register("userSettings", typeof(UserSettings), typeof(MainWindow), new PropertyMetadata(UserSettings.Default));
Now, you can bind userSettings by:
Value="{Binding userSettings.SomeUserSettingHere, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
And make sure you save UserSettings when you change them or on Exit by:
UserSettings.Default.Save();

Resources