Finding controls in WPF ControlTemplate - c#

I have created class that inherits from Window and I am applying control template to it:
public class BaseSearchWindow : Window {
static BaseSearchWindow() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(BaseSearchWindow), new FrameworkPropertyMetadata(typeof(BaseSearchWindow)));
}
public BaseSearchWindow() {
Uri uri = new Uri("/WPFLibs;component/Resources/StyleResources.xaml", UriKind.Relative);
ResourceDictionary Dict = Application.LoadComponent(uri) as ResourceDictionary;
this.Style = Dict["WindowTemplate"] as Style;
}
Than I want to find some control in control template:
public override void OnApplyTemplate() {
RibbonCommand searchCommand = this.Template.FindName("searchCommand", this) as RibbonCommand;
//doesn't work, searchCommand is null
searchCommand.CanExecute += CanExecuteRibbonCommand;
}
But it is allways null.
I tried it in inherited class and it works, but I want it in my base class, so I don't have to search for it every time I use that class.
This works:
public partial class MainWindow : BaseSearchWindow {
public MainWindow() {
InitializeComponent();
RibbonCommand searchCommand = this.Template.FindName("searchCommand", this) as RibbonCommand;
searchCommand.CanExecute += CanExecuteRibbonCommand;
}

Using FindName in OnApplyTemplate is the correct way of doing it; I think it doesn't work because you forgot to call base.OnApplyTemplate().

My bet is that you are looking for a command that doesn't exist (or has a different name) or isn't a RibbonCommand.
That or you didn't specify x:FieldModifier="protected" for the command in xaml.

Actually, I made a mistake. When I try to find controls that are not RibbonCommands it worked, so now I find parent control first and than use VisualTreeHelper to find the RibbonCommand. Sorry about that, I was convinced that it worked only in extended class, but I guess I was too tired when I posted the question. Thank you for your help anyway.

Related

How to pass value to constructor from xaml?

I want to assign a value right when initializing a new UserControl:
public partial class MyUserControl : UserControl
{
public MyUserControl(int id)
{
InitializeComponent();
//.. do something with id
}
// ...
}
Is it possible to pass a value to constructor (id in my case) from xaml?
<CustomControls:MyUserControl />
(Yes I can define a dependency property or make the control in code behind, but that doesn't help)
Yeah, that's possible. You can create a user control programmatically. Then, you can use any constructor you want. Here's a sample:
Supposing, that we have a usercontrol, that assigns a value to textbox on initialization:
public ControlWithP(int i)
{
InitializeComponent();
tb.Text = i.ToString();
}
Add this control to page:
public SamplePage()
{
InitializeComponent();
ControlWithP cwp = new ControlWithP(1);
this.sp.Children.Add(cwp);
}
where sp is StackPanel control. Same thing with adding user control to Grid.
see the result.
Is this, what you wanted?
From XAML-2009 you could do this with x:Arguments Directive but Windows Phone is using 2006 (for now) so it is not possible.
So to use your control from XAML you need a default contructor (parameterless).
I think you could use a little workaround, by using specially designed property for this:
public partial class MyControl : UserControl
{
private string myValue = "Default";
public string MyValue
{
get { return myValue; }
set
{
myValue = value;
// alternatively you can add some code here which
// will be invoked after control is created
}
}
public MyControl()
{
InitializeComponent();
}
}
then in XAML:
<local:MyControl MyValue="From xaml"/>
Just after the control is created, the property is set and its code invoked - so it can alternatively be used as additional part of code run during creation.
If you want to pass data to your control, better choice would be DependencyProperty - example here.

Set the same background in all windows forms with a single setting

i have 40 windows forms in a C# Project. i have to set the same background in all forms. is any option or settings to do that in a single settings?
You can create base form and set the background for it and other form inherit from the base form.
class baseForm: Form {
void base() {
this.BackColor = //set here
}
}
class YourForm : baseForm {
}
Just as an alternative, if you cannot use inheritence then you can refactor the code that applies the styling into a single place and then you only need to apply one line to every form. In fact with a little syntactic sugar (aka an extension method) you can make it look it was always part of your class anyway
i.e.
//Example form with an inheritor that blocks us from using inheritence to apply style
public class MainForm : 3rdPartyLibrary.WizardForm
{
public MainForm()
{
ApplyStyle();
}
}
//Normal form
public class MyDialog : Form
{
public MyDialog()
{
ApplyStyle();
}
}
public static class WinFormExtension
{
public static void ApplyStyle(this Form form)
{
form.BackColor = Colors.NavyBlue;
//etc
}
Work with Inheritance.
Create a Basic form, set the background property and inherit with all forms to the Basicform.
But im not sure, if the Visual Studio Gui-Desginer can handle Inheritance.
Inheritance is the right way to go about this, but sometimes it's fun to do things the wrong way too (though not in production of course):
var type = typeof (Color).Assembly.GetType("System.Drawing.KnownColorTable");
var field = type.GetField("colorTable",
BindingFlags.NonPublic | BindingFlags.Static);
var colorTable = (int[]) field.GetValue(null);
colorTable[(int) KnownColor.Control] = Color.Blue.ToArgb();
colorTable[(int) KnownColor.ControlText] = Color.Red.ToArgb();
new Form {Controls = {new Button {Text = "Success!"}}}.ShowDialog();
We solved this issue by adding the color code in your base form load function, which is inherited to child forms without issues.
private void BaseForm_Load(object sender, EventArgs e)
{
// put your color code here
}

How can I change the Title from a Usercontrol in another cs?

I have made a UserControl button named UserControl1, and I am trying to change its title from the templates where I am copying it (much like the easy clock-devise but one little step ahead).
I can not seem to do it. I write this code in the UserControl1, :
public string Display
{
get { return label1.Text; }
set { label1.Text = value; }
}
Then, I write this in the form, within the public class:
UserControl1.Display = "Title";
It shows an error at the "=" sign:
Invalid token '=' in class, struct, or interface member declaration.
I have a feeling im really close, can someone help me out?
I think you have a code like this...
class someClass
{
UserControl1.Display = "Title";
}
You cannot directly put your code inside a class like this, you have to create a method and then write this code inside that. For ex, change your code as below...
class someClass
{
UserControl1 uc = new UserControl1();
public void some_Method()
{
uc.Display = "Title";
}
}

Are there any caveats to swapping out DesignMode for LicenseManager.UsageMode in a WinForms UserControl constructor?

If you have a Form that displays data, one thing you can do is reference this.DesignMode in the constructor to avoid populating it in the designer:
public partial class SetupForm : Form
{
private SetupItemContainer container = new SetupItemContainer();
public SetupForm()
{
InitializeComponent();
if (!this.DesignMode)
{
this.bindingSource1.DataSource = this.container;
this.Fill();
}
}
}
However, if you decide to re-write that form as a UserControl, keeping the same constructor logic, something unexpected happens - this.DesignMode is always false no matter what. This leads to the designer invoking your logic that's meant to happen at runtime.
I just found a comment on a blog post that seem to give a fix to this but it references functionality of the LicenseManager class as a replacement that works as expected in a UserControl.
So for a UserControl I can do:
public partial class AffiliateSetup : UserControl
{
private AffiliateItemContainer container = new AffiliateItemContainer();
public AffiliateSetup()
{
InitializeComponent();
if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
{
this.bindingSource1.DataSource = this.container;
this.Fill();
}
}
}
Does using the LicenseManager instead of DesignMode have any caveats or implications that might dissuade me from putting in my production code?
According to someone who posted a comment on my answer to another question, using LicenseManager doesn't work in an OnPaint method.

Create a designer-aware UserControl collection to be used runtime

I have a Panel I want to fill with some UserControl(s) at runtime. These controls are complex and may be interdependent, so I'd like them:
to be editable with Visual Studio designer;
to be in the same context (= defined in the same class);
Both of the requirements are a must-have.
Considering UserControl is itself an indexed collection of Control(s), I started designing my controls in the same class, without caring about real positioning of them (that will be specified runtime). I already used the same identical approach with DevComponents ribbon containers (with much satisfaction), so I initially thought the same was possible with standard UserControl(s).
I eventually realized that a Control can be inside only one Control.ControlCollection instance at a time, so I couldn't use the Controls property and add controls to another panel without removing them from the original "dummy" UserControl.
My question is: is there a clean and supported way to create this designer-aware UserControl collection? I would call this approach a pattern because it really adds code clearness and efficiency.
Thanks,
Francesco
P.S.: as a workaround, I created a DummyControlContainer class that inherits UserControl and keeps a Dictionary map filled at ControlAdded event (code follows). Wondering if there's something cleaner.
public partial class DummyControlContainer : UserControl
{
private Dictionary<string, Control> _ControlMap;
public DummyControlContainer()
{
InitializeComponent();
_ControlMap = new Dictionary<string, Control>();
this.ControlAdded += new ControlEventHandler(DummyControlCollection_ControlAdded);
}
void DummyControlCollection_ControlAdded(object sender, ControlEventArgs args)
{
_ControlMap.Add(args.Control.Name, args.Control);
}
public Control this[string name]
{
get { return _ControlMap[name]; }
}
}
After testing and using it in a real world project, I'm more and more convinced that my solution was clean and safe if you need such a pattern. This container is intended to be filled with controls such as panels or similar. To prevent some bad behaviors with bindable data sources, I provided each new control added to this container with its own BindingContext. Enjoy.
public partial class DummyControlContainer : UserControl
{
private Dictionary<string, Control> _ControlMap;
public DummyControlContainer()
{
InitializeComponent();
_ControlMap = new Dictionary<string, Control>();
this.ControlAdded +=
new ControlEventHandler(DummyControlCollection_ControlAdded);
}
void DummyControlCollection_ControlAdded(object sender,
ControlEventArgs args)
{
// If the added Control doesn't provide its own BindingContext,
// set a new one
if (args.Control.BindingContext == this.BindingContext)
args.Control.BindingContext = new BindingContext();
_ControlMap.Add(args.Control.Name, args.Control);
}
public Control this[string name]
{
get { return _ControlMap[name]; }
}
}

Categories

Resources