I am creating a common animation function for all WPF Controls like TextBlock, Grid, TextBox... like below
private void animateFadeOut(*** displayObj)
{
displayObj.Opacity = 1;
System.Windows.Media.Animation.DoubleAnimation fadingAnimation = new System.Windows.Media.Animation.DoubleAnimation();
fadingAnimation.From = 1;
fadingAnimation.To = 0;
fadingAnimation.Duration = new Duration(TimeSpan.FromSeconds(0.5));
displayObj.BeginAnimation(TextBlock.OpacityProperty, fadingAnimation);
}
So I just want to know that which class should i write in place of ***. I tried UserControl, Object but I got issue in UserControl for Converting TextBlock or Grid to UserControl. And in Object, there is no Opacity value. So what is the best way to handle this?
Highest common ancestor for Grid, TextBlock and TextBox is FrameworkElement but if you want to animate Opacity then it's property of even higher class UIElement
private void animateFadeOut(UIElement displayObj)
{
displayObj.Opacity = 1;
System.Windows.Media.Animation.DoubleAnimation fadingAnimation = new System.Windows.Media.Animation.DoubleAnimation();
fadingAnimation.From = 1;
fadingAnimation.To = 0;
fadingAnimation.Duration = new Duration(TimeSpan.FromSeconds(0.5));
displayObj.BeginAnimation(UIElement.OpacityProperty, fadingAnimation);
}
Though not sure if your code would work for Grid also, but the class you are looking for is "UIElement"
You can check their Inheritance Hierarchy on MSDN.
E.g. for Grid:
Inheritance Hierarchy
System.Object
System.Windows.Threading.DispatcherObject
System.Windows.DependencyObject
System.Windows.Media.Visual
System.Windows.UIElement
System.Windows.FrameworkElement
System.Windows.Controls.Panel
System.Windows.Controls.Grid
System.Windows.Controls.Primitives.SelectiveScrollingGrid
They all under System.Windows.Controls namespace, but I found out that use FrameworkElement is better (as in my case I need to invoke BringIntoView()). You could check the hierarchy and decide by yourself. But AFAIK, FrameworkElement should be used as it provides everything (property and method) you may need to get access to in your situation.
Related
If I create a class and make it derive from a ListView like this...
class MyListView : ListView
{
public MyListView() : base()
{
DoubleBuffered = true;
OwnerDraw = true;
Cursor = Cursors.Hand;
Scrollable = false;
}
protected override void OnDrawItem(DrawListViewItemEventArgs e)
{
//base.OnDrawItem(e);
}
}
Then I open the design view of my windows form and add a new MyListView object then add a single item and link it to a image list. I can see that there is one item in the mylistview object. It has no effect on the object I have on my form called lv of type MyListView. When I run my app on the other hand I see exactly what I expected and there is no items listed.
Why would this effect run-time and not design-time painting?
The answer
ListViewDesigner shadows OwnerDraw property like Visible or Enabled property of control. So it just works at run-time and changing it doesn't affect design-time.
Side Note
If you take a look at source code of ListViewDesigner, you will see this property:
private bool OwnerDraw
{
get { return (bool) base.ShadowProperties["OwnerDraw"]; }
set { base.ShadowProperties["OwnerDraw"] = value; }
}
And in PreFilterProperties you will see the designer replaced the original property with this one:
PropertyDescriptor oldPropertyDescriptor = (PropertyDescriptor) properties["OwnerDraw"];
if (oldPropertyDescriptor != null)
{
properties["OwnerDraw"] = TypeDescriptor.CreateProperty(typeof(ListViewDesigner),
oldPropertyDescriptor, new Attribute[0]);
}
So it doesn't matter what View you use, it performs the default painting regardless of what you have in OnDrawItem. It's because it doesn't use OwnerDraw property at design-time. The designer shadows it. This is the same behavior which you see for Enabled or Visible property.
Workaround to enable owner-draw at run-time
As a workaround, you can register a different Designer for your derived control. This way the OwnerDraw property will work as a normal property:
[Designer(typeof(ControlDesigner))]
public class MyListView : ListView
Warning: Keep in mind, by registering a new designer for the control, you will lose the current ListViewDesigner features like its designer verbs or its smart tag (actions list) window or Column Sizing options. If you need those features, you can implement those features in a custom designer by looking into ListViewDesigner source code.
I am trying to add tooltip to all controls in my WPF application i tried
foreach(IRegion region in _RegionManager.Regions)
{
foreach(IView view in region.Views)
{
foreach(Control c in view.)//here my problem
c.ToolTip = "some tooltip";
}
}
That did not work because i have not any idea where I should looking for controls in that case.
Thank you for any advice.
In WPF, views should be defined in declarative way via XAML markup.
You would normally define your tooltips in your views:
<UIElement ToolTip="toolTipContent"/>
Of course, you can use bindings:
<UIElement ToolTip="{Binding ToolTipText}"/>
Note, that Prism's IView interface doesn't provide any information about the actual type of the view instance. It could be a Page, an UserControl or even a TextBox.
You can, if you want to, use linq and get only those views, which are e.g. UserControls:
foreach(UserControl view in region.Views.OfType<UserControl>())
{
// do something...
}
But that doesn't really help you, since in WPF there's no such easy way to iterate through child elements of an UserControl, as we did it in in Windows Forms.
You could use the VisualTreeHelper and traverse your visual tree looking for the child elements, but that's awkward:
void GetChildControls(IList<Visual> container, Visual parent)
{
int childCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childCount; i++)
{
Visual visual = (Visual)VisualTreeHelper.GetChild(parent, i);
container.Add(visual);
if (VisualTreeHelper.GetChildrenCount(visual) > 0)
{
GetChildControls(container, visual);
}
}
}
I've found similar answers to my question before, but not quite to what I'm trying to do...
In Visual Basic (last I used it, in 06/07) there was an "Index" property you could assign to multiple controls with the same name. I used this primarily to loop through controls, i.e.:
For i = 1 to 500
picSeat(i).Print "Hello"
Next i
Is there a way to do this in C#? I know there is a .IndexOf(), but would that really help for what I'm doing? I want to have multiple controls with the same name, just different index.
This is a Windows Form Application, and I'm using Visual Studio 2012. I am talking about controls, not arrays/lists; this was possible in VB and I was wondering if it was possible at all in C#. So I want to have, say, 30 seats in a theatre. I want to have each seat represented by a picturebox named "picSeat". VB would let me name several objects the exact same, and would assign a value to a control property "Index". That way, I could use the above loop to print "Hello" in every picture box with only 3 lines of code.
No, this feature does not exist in C#, and was never implemented in the transition from classic VB to VB.Net.
What I normally do instead is put each of the controls in question in a common parent container. The Form itself can work, but if you need to distinguish these from others of the same type a GroupBox or Panel control will work, too. Then, you access the controls like this:
foreach (var picBox in parentControl.Controls.OfType<PictureBox>())
{
// do something with each picturebox
}
If you want to use a specific control, just write by name:
pictureBox6.SomeProperty = someValue;
If you need to change a specific control determined at run-time, normally this is in response to a user event:
void PictureBox_Click(object sender, EventArgs e)
{
var picBox = sender As PictureBox;
if (picBox == null) return;
//picBox is now whichever box was clicked
// (assuming you set all your pictureboxes to use this handler)
}
If you really really want the Control Arrays feature, you can do it by adding code to create the array to your form's Load event:
PictureBox[] pictureBoxes = Me.Controls.OfType<PictureBox>().ToArray();
Are we talking WinForms here? I'm not sure, but I don't think you can have multiple controls in winforms with same name. But I vaguely recall doing something similar and the solution was to name them Button_1, Button_2 etc. Then you can iterate through all controls and get your own index.
Beware though that if you want to instanciate a separate control for each seat in a theatre, you might run into some serious performance issues :) I've done something similar to that as well and ended up drawing the whole thing on a canvas and using mouse coordinates to handle the events correctly.
You may want to check out the Uid property of controls.
(http://msdn.microsoft.com/en-us/library/system.windows.uielement.uid(v=vs.110).aspx)
You can access Control through Uid property with the following
private static UIElement FindUid(this DependencyObject parent, string uid)
{
var count = VisualTreeHelper.GetChildrenCount(parent);
if (count == 0) return null;
for (int i = 0; i < count; i++)
{
var el = VisualTreeHelper.GetChild(parent, i) as UIElement;
if (el == null) continue;
if (el.Uid == uid) return el;
el = el.FindUid(uid);
if (el != null) return el;
}
return null;
}
And simply use
var control = FindUid("someUid");
I copied code from this post
If you create an indexed dictionary of your user control, it will behave pretty much the same as in VB6, though you'll not see it on the VS C# GUI. You'll have to get around the placement issues manually. Still - and most importantly -, you'll be able to refer to any instance by the index.
The following example is for 3 pieces for clarity, but of course you could automate every step of the process with appropriate loops.
public partial class Form1 : Form
{
...
Dictionary<int, UserControl1> NameOfUserControlInstance = new Dictionary<int, UserControl1>()
{
{ 1, new UserControl1 {}},
{ 2, new UserControl1 {}},
{ 3, new UserControl1 {}}
};
private void Form1_Load(object sender, EventArgs e)
{
NameOfUserControlInstance[1].Location = new System.Drawing.Point(0, 0);
NameOfUserControlInstance[2].Location = new System.Drawing.Point(200, 0);
NameOfUserControlInstance[3].Location = new System.Drawing.Point(400, 0);
Controls.Add(NameOfUserControlInstance[1]);
Controls.Add(NameOfUserControlInstance[2]);
Controls.Add(NameOfUserControlInstance[3]);
}
...
}
I like using Tags to apply any type of meta data about the controls
for (int i = 0; i< 10; ++i)
{
Button button = new Button();
button.Tag = i;
}
I have a control in an assembly that I can't change that is very similar to the .NET DateTimePicker. I want to hide the time picker portion of that control when a certain condition is met (Property value on my ViewModel). The control looks like this:
[TemplatePart(Name = "PART_DatePicker", Type = typeof (DatePicker))]
[TemplatePart(Name = "PART_TimePicker", Type = typeof (TimePicker))]
public class MyDateTimePicker : Control {/*...*/}
This answer shows a nice way to always hide a PART of a control, but I want to do it dynamically:
How to hide a part of a WPF control
I imagine there are a few ways to do this. What I want is something minimal (like in the linked question's answer) as well as something that doesn't violate MVVM. System.Interactivity behaviors and triggers are fair game.
Create a new control extending the previous one
public sealed class MySuperiorDateTimePicker : MyDateTimePicker
{
//....
Add a DependencyProperty that you can bind to your ViewModel's state
public static readonly DependencyProperty HideItProperty =
DependencyProperty.Register(
"HideIt",
typeof(bool),
typeof(MySuperiorDateTimePicker ),
new UIPropertyMetadata(false, HideItPropertyChanged));
//snip property impl
Wait for the property to change, then hide your UI
private static void HideItPropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
(d as MySuperiorDateTimePicker).OnHideItChanged((bool)e.OldValue,
(bool)e.NewValue);
}
private void OnHideItChanged(bool oldValue, bool newValue)
{
if(BusyTemplate == null)
return;
FindTimePicker().Visibility = newValue ? Visibility.Visible :
Visibility.Collapsed;
}
private UIElement FindTimePicker()
{
//snip null checks
return GetTemplateChild("PART_TimePicker") as UIElement;
}
Be careful with FindTimePicker as your DP might change before the control is loaded, and GetTemplateChild will return null. The usual thing to do is, in OnHideItChanged, if GetTemplateChild returns null use Dispatcher.BeginInvoke to re-run the event handler later on (ApplicationIdle or earlier).
When you find yourself saying "How can I do UI work using MVVM" stop and rethink your true goals. MVVM != no codebehind, no custom controls, etc.
One solution would be to hide it with the help of a DataTrigger defined in the datatemplate, so that when a certain value in the datacontext of the control is set to true/false then you will hide/show the part.
A quick search and i found some links that you might find useful:
http://zamjad.wordpress.com/2010/06/22/conditionally-hide-controls-from-data-template/
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/ae2dbfb7-5dd6-4352-bfa1-53634289329d/
The solution that worked for me was to edit the style of the control. Using Blend, I edited a copy of the style of the DateTimePicker, and added a binding to Visibility of the TimePicker that looks at my VM and converts the value of the enumeration.
We have a user control with a custom dependency property (DP). The DP is bound to an ObservableCollection.
When a new item is added to the collection programatically, the databinding does not update the target DP. Why? We think it's because, unfortunately, in our case the target is not a ListBox or ListView, but a Canvas. The DP, when changed or initialized, is supposed to draw a Shape (!) onto the Canvas, and the shape's position and size is bound to the collection item's two properties: WIDTH, LEFT.
Ideally we don't want to clear the Canvas and redraw all items just becasue one has been added (or deleted). But how?
So:
How can the custom DP take care of drawing the shape for the new collection item? What callback do we need, at what point in time does this have to happen, and what specific MetaDataOptions might there?
Also, are there any good resources out there concerning all these dependency property options. They are quite confusing. MSDN does not really help with what we're trying to do.
Thanks!
EDIT:
The ObservableCollection is like so:
public class Projects : ObservableCollection<Project>
{
//no ommitted code. this class really IS empty!
}
The DP is like so:
public class MyUserControl : UserContorl
{
public static readonly DependencyProperty... etc. typeof(Projects)
private static void OnProjectsChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyUserControl u = d as MyUserControl;
CpProjectCollection projects = e.NewValue as CpProjectCollection;
u.Refresh(projects);
}
private void Refresh(CpProjectCollection projects)
{
foreach (CpProject p in projects)
{
//...add each project to the Canvas
ProjectContorl pc = new ProjectControl();
pc.Project = project;
Binding b = new Binding("StartTime");
b.Converter = new TimeSpanConverter();
b.Source = pc.Project;
b.Mode = BindingMode.TwoWay;
c.SetBinding(Canvas.LeftProperty, b);
//do the same for project duration
}
}
}
If you bind to ObservableCollection, you get the change notification if the collection is replaced with another collection, not when the collection's content is changed. So, you'll need to subscribe to CollectionChanged event in your code-behind.
If you subscribe to CollectionChanged, you can see which are the new/deleted items in your ObservableCollection. You can add a new shape for each new item and remove old shapes for deleted items.