How to bind button content to the static readonly field - c#

I have a class MainWindow.xaml.cs:
namespace HomeSecurity {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged {
public static readonly string START = "start", RESET = "RESET";
.....
}
There is a button in MainWindow.xaml:
<Button x:Name="AcceptCamerasButton" Content="{x:Static local:MainWindow.START}" Grid.Row="1" Click="AcceptCamerasButton_Click"></Button>
How to set content of that button to MainWindow.Start? Current version does not work.
EDIT:
I have declared:
xmlns:local="clr-namespace:HomeSecurity"
but still when I use:
<Button x:Name="AcceptCamerasButton" Content="{x:Static local:MainWindow.START}" Grid.Row="1" Click="AcceptCamerasButton_Click"></Button>
I get:
Error 1 The member "START" is not recognized or is not accessible.

You cannot bind to fields. Bindings only work on properties. So you can either change the definition of START to a property, or create a property wrapper that returns the value of START and bind to that instead.
public static string START
{
get { return "start"}
}
public static string RESET
{
get { return "RESET"; }
}
Or, if you prefer to keep the readonly backing field:
private static readonly string startField = "start";
public static string START
{
get { return startField}
}
Also, I'm assuming that you've already done this, but I'm including this anyway, make sure you include the namespace declaration in the XAML file for the local namespace to point to the local assembly and appropriate namespace.
xmlns:local="clr-namespace:YourProjectAssemblyName..."

Related

Update XAML TextBlock with value of public property from other class

I have in my C# WPF solution as follows:
Mainwindow with a startupControl (always running)
Dialogwindow with diffent other controls.
A public Helper-class containing some public static properties to indicate what department at customer is active, and for who i have focus on at the moment.
I want simply two XAML textBlocks displayed in my Startupcontrol to show the property names if and when the value for a department or costumer has been set.
I think it could properbly work smooth with some sort of binding, but i dont know anything about bindings, other than they exists.
Is it possible in any way from my controls in my dialogwindow, to change the value of the 2 textblocks in the Startupcontrol ?
As the program is small and I know exactly when the values change, I think i could make a function setting the value ex.:
activeDepartmentTextBlock.Text = HelperClass.ActiveDepartment.Name;
But from my control.cs in the DialogWindow, it seems to be possible to reach the activeDepartmentTextBlock.
Anyone who can help me ?
Since WPF 4.5, binding to static properties with property change notification is quite simple.
The example below assumes that you want to notify about the change of the ActiveDepartment property of the HelperClass (and not about the Name property of the Department object). In addition to the static property, declare a static event named StaticPropertyChanged and fire it when the static property changes:
public class Department
{
public string Name { get; set; }
}
public class HelperClass
{
public static event PropertyChangedEventHandler StaticPropertyChanged;
private static Department activeDepartment;
public static Department ActiveDepartment
{
get => activeDepartment;
set
{
activeDepartment = value;
StaticPropertyChanged?.Invoke(null,
new PropertyChangedEventArgs(nameof(ActiveDepartment)));
}
}
}
You can bind to a static property like this:
<TextBlock Text="{Binding Path=(local:HelperClass.ActiveDepartment).Name}"/>
Binding is a good solution but you have static property so you can't use binding infrastructure directly to get notified of updates since there's no DependencyObject (or object instance that implement INotifyPropertyChanged) involved.
If the value does change and you need to update TextBlock's value in main window yo can create a singleton instead of static class to contain the value and bind to that.
An example of the singleton:
public class HelperClass : DependencyObject {
public static readonly DependencyProperty ActiveDepartmentProperty =
DependencyProperty.Register( "ActiveDepartment", typeof( Department ),
typeof( HelperClass ), new UIPropertyMetadata( "" ) );
public Department ActiveDepartment {
get { return (Department) GetValue( ActiveDepartmentProperty ); }
set { SetValue( ActiveDepartmentProperty, value ); }
}
public static HelperClass Instance { get; private set; }
static HelperClass() {
Instance = new HelperClass();
}
}
So binding will work like in an example below:
<TextBox Text="{Binding Source={x:Static local:HelperClass.Instance}, Path=ActiveDepartment.Name}"/>
It might look like a hard way and that’s it. You can use events model instead and add the event to your HelperClass. MainWindow can add event handler and change activeDepartmentTextBlock value when event raised.
public MainWindow()
{
InitializeComponent();
HelperClass.Instance.DepartmentChanged += OnDepartmentChanged;
}
private void OnDepartmentChanged(Department newDepartment)
{
activeDepartmentTextBlock.Text = newDepartment.Name;
}
Update. If you want to have the simplest solution you can break encapsulation principle and pass MainWindow as a parameter to DialogWindow and make activeDepartmentTextBlock public. So you will be able to save the link to the MainWindow in the DialogWindow's field and just change the text when you need in DialogWindow:
this.mainWindow.activeDepartmentTextBlock.Text = HelperClass.ActiveDepartment.Name;

How to bind Entry to Xam.Plugins.Settings using BindingContext

Binding seems somewhat more confusing in Xamarin Forms compared to C#. I installed Xam.Plugins.Settings. I simply want to bind bind an <Entry> to one of my settings. Here's what I have in my XAML:
<Grid BindingContext="{HelloWorld.Helpers.Settings}">
...
<Entry Placeholder="ESN"
Text="{Binding Path=Esn, Mode=TwoWay}"
...
/>
</Grid>
And here's my code behind:
namespace HelloWorld.Helpers
{
public static class Settings
{
private static ISettings AppSettings
{
get
{
return CrossSettings.Current;
}
}
#region Setting Constants
private const string EsnKey = "esn_key";
private static readonly string EsnDefault = string.Empty;
#endregion
public static string Esn
{
get
{
return AppSettings.GetValueOrDefault<string>(EsnKey, EsnDefault);
}
set
{
AppSettings.AddOrUpdateValue<string>(EsnKey, value);
}
}
}
}
But I'm getting the error: Position 7:15. Type HelloWorld.Helpers.Settings not found
This tutorial shows an example of how to set the BindingContext dynamically, but as you can see, the Settings class is static, and so I can't call new. I also want to be able to set the binding in the XAML. I then referred to this tutorial, so I tried to set the value of BindingContext in the XAML to {x:Static HelloWorld.Helpers.Settings}, but I get the same error.
All I want to do is map HelloWorld.Helpers.Settings.Esn to this <Entry>.
Any advice? I'm totally new to Xamarin, and I have very little C# experience.
Thanks in advance!
Update 1 5/26
#Alessandro solution works. I prefer not to have to write getters and setters again, since they're already written in Settings, but it works. I didn't have to use INPC though. Here is the code for my ContentPage in case anyone else has the same issue. Thanks.
namespace HelloWorld
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Configuration : ContentPage
{
public Configuration()
{
InitializeComponent();
BindingContext = new MySettings();
}
}
public class MySettings
{
public string Esn
{
get { return HelloWorld.Helpers.Settings.Esn; }
set { HelloWorld.Helpers.Settings.Esn = value; }
}
}
}
And then I removed the BindingContext property from within my XAML, since it's being set in the code behind.
Update 2 5/26
I just changed public static class Settings to public class Settings and public static string Esn to public string Esn. Then that prevents the need for MySettings. And instead I write BindingContext = new Settings();
I'm not sure why the plugin developer used static instead, but it was a simple solution it seems.
I think you should use a Class "MySettings" that use "Settings" and implement INotifyPropertyChanged (I use PropertyChanged.Fody for INPC)
[ImplementPropertyChanged]
public class MySettings
{
public string Url {
get { return Settings.Url; } // These are yours "Settings"
set { Settings.Url = value; }
}
public int Port {
get { return Settings.Port; }
set { Settings.Port = value; }
}
}
Remove static keywords from public static class Settings and public static string Esn
In the constructor for your ContentPage, add BindingContext = new Settings()
Remove the BindingContext property from the XAML
That's it.

Get the current filename from a Visual Studio text adornment extension

I'm new to VS extension development. I'm currently working with the text adornment sample in VS 2015 and have been able to get coloured boxes showing correctly. Now I want to extend the sample so the adornment only appears on certain file names.
Googling has said I can use ITextDocumentFactoryService.TryGetTextDocument interface with the IWpfTextView.TextBuffer property to get a filename. This sounds great. But I can't seem to actually get the interface.
In my class I have:
[Import]
public ITextDocumentFactoryService TextDocumentFactoryService = null;
But it is always NULL.
How can I get ITextDocumentFactoryService?
namespace Test
{
internal sealed class TestAdornment
{
[Import]
public ITextDocumentFactoryService TextDocumentFactoryService = null;
public TestAdornment(IWpfTextView view)
{
}
/// <summary>
/// Adds the scarlet box behind the 'a' characters within the given line
/// </summary>
/// <param name="line">Line to add the adornments</param>
private void CreateVisuals(ITextViewLine line)
{
// TextDocumentFactoryService is NULL
}
}
}
TextAdornmentTextViewCreationListener.cs
[Export(typeof(IWpfTextViewCreationListener))]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal sealed class TextAdornmentTextViewCreationListener : IWpfTextViewCreationListener
{
[Import]
public ITextDocumentFactoryService textDocumentFactory { get; set; }
//...
public void TextViewCreated(IWpfTextView textView)
{
new TextAdornment(textView, textDocumentFactory);
}
}
TextAdornment.cs
internal sealed class TextAdornment
{
private readonly ITextDocumentFactoryService textDocumentFactory;
private ITextDocument TextDocument;
//...
public TextAdornment(IWpfTextView view, ITextDocumentFactoryService textDocumentFactory)
{
//...
this.textDocumentFactory = textDocumentFactory;
//...
}
internal void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
{
var res = this.textDocumentFactory.TryGetTextDocument(this.view.TextBuffer, out this.TextDocument);
if (res)
{
//this.TextDocument.FilePath;
}
else
{
//ERROR
}
}
}
You got it via dependency injection.
As you only submitted 2 lines of code I suppose your context is set up, either explicitly by you, either implicitly by some environment who calls your code.
You should declare property instead of field
It should be public
Then automagically big brother will set it for you before you first access to it.
...or...
You can use constructor injection instead. Note: It is not you who will create your class.
private readonly ITextDocumentFactoryService _textDocumentFactoryService;
[ImportingConstructor]
internal YourClass(ITextDocumentFactoryService textDocumentFactoryService)
{
_textDocumentFactoryService = textDocumentFactoryService;
}
So in my case I needed to put the import statement into the AdornmentTextViewCreationListener. This implements IWpfTextViewCreationListener and is the one with the following decorating the class.
[Export(typeof(IWpfTextViewCreationListener))]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Document)]
Then I can add
private readonly ITextDocumentFactoryService _textDocumentFactoryService;
[ImportingConstructor]
to my class

INotifyPropertyChanged binding not updating as expected

So here is the problem I'm beating my head against: I have a custom user control that exposes two dependency properties that are bound to my ViewModel. In my ViewModel I have an instance of a class that holds multiple properties that express values that relate to the user control as well as to items that control manipulates. Here's a bit of sample code to explain it visually so here is a simple sample of my control, it's a Slider that is combined with a checkbox that allows the user to lock the slider.
<custom:SliderControl IsLocked="{Binding Path=CustomClass.IsLocked, Mode=TwoWay}" SliderValue="{Binding Path=CustomClass.Value, Mode=TwoWay}" />
IsLocked and SliderValue are dependency properties that effectively manipulate the checkbox and slider that are contained in the custom control. All of the control functions work as intended, except for the bindings to the class I've defined. If I create individual properties, as in one int property and one bool property the bindings work as intended. However I have five sliders, and each slider in my actual code has five properties that tie in to them. I'm trying to eliminate code duplication by creating a class to hold these properties in a reusable object shrinking my 25 properties down to 5 class instances.
My CustomClass inherits ObservableObject and has a bool property and int property named IsLocked and SliderValue respectively. For more visual aids here is what it looks like:
public class CustomClass : ObservableObject
{
public const string SliderValuePropertyName = "SliderValue";
private int _sliderValue= 0;
public int SliderValue
{
get
{
return _sliderValue;
}
set
{
if (_sliderValue== value)
{
return;
}
_sliderValue= value;
RaisePropertyChanged(SliderValuePropertyName );
}
}
public const string IsCheckedPropertyName = "IsChecked";
private bool _isChecked = false;
public bool IsChecked
{
get
{
return _isChecked;
}
set
{
if (_isChecked == value)
{
return;
}
_isChecked = value;
RaisePropertyChanged(IsCheckedPropertyName);
}
}
The ViewModel property is very similar and looks like this, an new instance of the class is created when the ViewModel loads:
public const string SliderOnePropertyName = "SliderOne";
private CustomClass _sliderOne;
public CustomClass SliderOne
{
get
{
return _sliderOne;
}
set
{
if (_sliderOne== value)
{
return;
}
_sliderOne= value;
RaisePropertyChanged(SliderOnePropertyName );
}
}
Why won't the updating of the dependency property that is bound to the property in the class update properly? Is it because you can't properly update the class instance property by itself and instead have to update the entire class instance whenever changes occur? Or do I need to further customize the setter in this ViewModel property? As it sits now changing the slider value or checkbox never hits the bound property at all and nothing errors out when debugging.
EDIT: I've also surrounded the control in a Border and set the Border UIElement's DataContext to that of the class and then subsequently applied the more simple path binding to the underlying custom control. This however did not have any effect on my problem.
I'm a homegrown programmer so I often miss things when putting code together and I'm guessing this is the case here, unless what I'm trying just won't work.
Any help would be greatly appreciated.
EDIT: So I've been toying around with using a custom event that will let me know when the specific property of the custom control changes and then having that event wired up in my ViewModel to update the existing class. This works but still creates code duplication as now I have to have 10 events, 2 events per control, one to check for when the value of the slider changes and the other to detect when the checkbox IsChecked value changes. This code duplication exists since you can't route multiple command parameters (like a simple string identifier for which slider is being manipulated as well as the value you want to use in the code). This limitation means I can't just use 2 events that differentiate between which control is undergoing changes within the defined method as exposing the physical control to the ViewModel breaks the MVVM pattern. Using a class as the datacontext for the user control made it so I didn't care what control was being manipulated as they each had their own class instance. Using events this unravels the MVVM pattern as now I need to know which of the five controls is being manipulated by the user.
It can't be this hard to use a class in property bindings. I have to be missing something remedial.
here is a full example:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
public class ViewModel
{
public SliderValues slv { get; private set; }
public ViewModel()
{
slv = new SliderValues();
}
}
public class SliderValues : INotifyPropertyChanged
{
bool _isLocked = false;
public bool IsLocked
{
get { return _isLocked; }
set
{
_isLocked = value;
OnPropertyChanged("IsLocked");
}
}
int _theValue = 5;
public int TheValue
{
get { return _theValue; }
set
{
_theValue = value;
OnPropertyChanged("TheValue");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string prop)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
Now the xaml:
<UserControl x:Class="TestBindings.MainPage"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Slider Height="23" HorizontalAlignment="Left" Margin="114,138,0,0" Name="slider1" VerticalAlignment="Top" Width="100"
DataContext="{Binding slv}" Value="{Binding TheValue, Mode=TwoWay}"/>
</Grid>
</UserControl>
May be there is just a syntactical error. Try this
{Binding Path=CustomClass.IsLocked, Mode=TwoWay}
Try this...<custom:SliderControl DataContext="{Binding CustomClass}" IsLocked="{Binding IsLocked, Mode=TwoWay}" SliderValue="{Binding Value, Mode=TwoWay}" />

How to create a custom MessageBox?

I'm trying to make a custom message box with my controls.
public static partial class Msg : Form
{
public static void show(string content, string description)
{
}
}
Actually I need to place some controls (a gridview) in this form and I have to apply my own theme for this window, so I don't want to use MessageBox. I want to call this from my other forms like
Msg.show(parameters);
I don't wish to create an object for this form.
I know I can't inherit from Form class because it isn't static. But I wonder how MessageBox is implemented, because it is static. It is being called like MessageBox.show("Some message!");
Now I'm getting an error because inheritance is not allowed:
Static class 'MyFormName' cannot derive from type 'System.Windows.Forms.Form'. Static classes must derive from object
How MessageBox is implemented then?
Your form class needs not to be static. In fact, a static class cannot inherit at all.
Instead, create an internal form class that derives from Form and provide a public static helper method to show it.
This static method may be defined in a different class if you don't want the callers to even “know” about the underlying form.
/// <summary>
/// The form internally used by <see cref="CustomMessageBox"/> class.
/// </summary>
internal partial class CustomMessageForm : Form
{
/// <summary>
/// This constructor is required for designer support.
/// </summary>
public CustomMessageForm ()
{
InitializeComponent();
}
public CustomMessageForm (string title, string description)
{
InitializeComponent();
this.titleLabel.Text = title;
this.descriptionLabel.Text = description;
}
}
/// <summary>
/// Your custom message box helper.
/// </summary>
public static class CustomMessageBox
{
public static void Show (string title, string description)
{
// using construct ensures the resources are freed when form is closed
using (var form = new CustomMessageForm (title, description)) {
form.ShowDialog ();
}
}
}
Side note: as Jalal points out, you don't have to make a class static in order to have static methods in it. But I would still separate the “helper” class from the actual form so the callers cannot create the form with a constructor (unless they're in the same assembly of course).
You don't need the class to be static.
Just do something like:
public partial class Msg : Form
{
public static void show(string content, string description)
{
Msg message = new Msg(...);
message.show();
}
}
You don't need to make the class static in order to call one of its methods statically — it's sufficient to declare the particular method as static.
public partial class DetailedMessageBox : Form
{
public DetailedMessageBox()
{
InitializeComponent();
}
public static void ShowMessage(string content, string description)
{
DetailedMessageBox messageBox = new DetailedMessageBox();
messageBox.ShowDialog();
}
}
We are using messageBox.ShowDialog() to have the form being displayed as a modal window. You can display the message box using DetailedMessageBox.ShowMessage("Content", "Description");.
By the way, you should rethink your naming and stick to a consistent naming pattern. Msg and show are weak names that do no match the Naming Guidelines — you would definitely want to check those out!
In a WPF project you can add a new window and call it MessageBoxCustom then inside C# the Void where you can find InitialiseComponent(); you add 2 properties and bind those properties to the textBlocks you should have created inside your XAML view
Example:
public MessageBoxCustom(string Message, string Title)
{
InitialiseComponent();//this comes first to load Front End
textblock1.Text = Title;
textblock2.Text = Message;
}
Just position your TextBlocks where you want them to be displayed in XAML
From your Main Window you can call that message box like this
private void Button_Click()
{
MessageBoxCustom msg = new MessageBoxCustom("Your message here","Your title her");
msg.ShowDialog();
}

Categories