Adding new items to WPF Ribbon via Code - c#

I'm using the WPF Office Ribbon, and I have a content view that I would like to have add new items to the ribbon when that view becomes active. I have code that adds a new RibbonCommand as well as a new RibbonButton to the group I want, but nothing happens when I add it. However, if I add a new group with the button, it comes up fine and is bound correctly. Is there some method to get it to update that I'm missing? I've tried UpdateLayout() and it does not work either. I'd really like to try and avoid rebuilding all the groups everytime the view changes.
Works:
public void InjectItems(IView view)
{
var ribbonCommands = ProcessRibbonCommands(view.GetViewModel().Tasks, view.GetType());
var group = new RibbonGroup();
group.Command = new RibbonCommand() { LabelTitle = "Group Test" };
foreach (RibbonCommand command in ribbonCommands)
{
shell.MainRibbon.Resources.Add(command.Name, command);
group.Controls.Add(new RibbonButton { Command = command });
}
shell.MainRibbon.SelectedTab.Groups.Add(group);
}
Doesn't Work:
public void InjectItems(IView view)
{
var ribbonCommands = ProcessRibbonCommands(view.GetViewModel().Tasks, view.GetType());
var group = shell.MainRibbon.SelectedTab.Groups[0]; //I have a default group, will fix later
foreach (RibbonCommand command in ribbonCommands)
{
shell.MainRibbon.Resources.Add(command.Name, command);
group.Controls.Add(new RibbonButton { Command = command });
}
}

I'm assuming you're using the Microsoft Ribbon CTP from the OfficeUI site.
As part of the licensing agreement there are a number of style guidelines that you are expected to follow. One of them is that you don't add/remove contents of the Ribbon based on your current view.
from the doc:
Controls displayed in a group MUST NOT change as a result of selection. If a control is not active, the
control MUST be grayed out, rather than removed from the group. This provides a more predictable
experience and prevents the layout of controls on the Ribbon from changing and distracting users.
that being said, it sounds like a Context tab is exactly what you're looking for. These can be disabled and enabled but the actual contents of the tab don't change.
This is the code to create a context tab in XAML:
<!--Context Groups-->
<r:Ribbon.ContextualTabGroups>
<!--Piece Contextual Group-->
<r:RibbonContextualTabGroup x:Name="grpPieceContext" Label="Piece Tools">
<r:RibbonTab Label="Piece Information" Name="tabPieceContextInfo">
<r:RibbonGroup Name="grpPieceDetails" Command="{StaticResource PieceInformationGrpCommand}">
<r:RibbonLabel x:Name="lblPieceTag"/>
<r:RibbonTextBox Name="txtPieceDescription" Command="{StaticResource PieceNameTextboxCommand}"
TextChanged="txtPieceDescription_TextChanged" MaxLength="32"/>
<r:RibbonLabel x:Name="lblPieceLocation"/>
</r:RibbonGroup>
</r:RibbonTab>
</r:RibbonContextualTabGroup>
</r:Ribbon.ContextualTabGroups>
you can then active and de-active the tab via this code:
if (!this.grpPieceContext.IsActive)
{
this.grpPieceContext.IsActive = true;
this.grpPieceContext.Color = Colors.Orange;
}
where orange is the color that sits in behind the context group.
Hope this helps

I ended up just deleting and recreating the group and entire tab if necessary.

Related

Xamarin.android GUI does not update after AddView

I am creating an application for Xamarin.android in c# and ran into an odd problem.
I use a wrapper class which inflates a view. After that I add the view to a linearlayout with AddView. Sometimes the gui doesn’t update for no apparent reason. The Elements aren’t added. When I call the task button (I don’t know if that’s the right name – the button left of the home button) and then navigate back to my app the elements will appear. I read somewhere that you could use Invalidate() to update the gui but that does not seem to work.
Any suggestions are highly appreciated.
This is my constructor of the wrapper class:
public BoxDisplay(MainActivity activity, Product product, ViewGroup root)
{
View = activity.LayoutInflater.Inflate(Resource.Layout.BoxItem, root, false);
shelf = View.FindViewById<TextView>(Resource.Id.Shelf);
name = View.FindViewById<TextView>(Resource.Id.Name);
barcode = View.FindViewById<TextView>(Resource.Id.Barcode);
Stock = View.FindViewById<EditText>(Resource.Id.Stock);
typ = View.FindViewById<TextView>(Resource.Id.type);
this.activity = activity;
SetProduct(product);
Stock.ClearFocus();
Stock.Click += (o, arg) =>
{
Stock.SelectAll();
};
Stock.EditorAction += EditorAction;
}
and here I add the view long after the activity was created:
private void GenerateView(List<Product> products)
{
var boxlist = FindViewById<LinearLayout>(Resource.Id.BoxList);
foreach (var product in products)
{
var box = new BoxDisplay(this, product, boxlist);
boxDisplays.Add(box);
box.EnableEditText(false);
boxlist.AddView(box.View);
box.View.Click += (sender, e) => { box.UpdateBox(); };
}
}
A couple of ideas more than an answer, and maybe could be bad practice, but I do not run into your issue :
I usually add programmatically created Views in OnViewCreated (Fragment) / OnCreate(Activity)
Make sure your LinearLayout has a parent. It must be added to a parent view (root Layout, another Layout, a scrollview, ...).
Make sure you do not have a blocking, manually launched thread involving UI update (even through RunOnUiThread), which could be unlocked by activity recreation.
Make sure your view isn't "flattened" by another existing one in your layout (for example having a view matching parent size in both dimensions)
Beside the fact that it won't display your layout, is your application running properly (no permanent freeze) ?

WPF User Control with Tab Control

I'm attempting to create a user control that houses a tab control.
My question is, how do I expose the tab control through the user control so we can add tabs?
The entire control will house three areas: command buttons at the top, the tab control, and a styled textblock that displays messages.
The command buttons will be configurable as dependencyproperties, so we may choose to show the apply button or not when we use the usercontrol. I'm strictly a designer and not a developer, so I'm trying to get my feet wet in building this control, but I'm in a little over my head.
I have no problem whipping up the XAML for what I'm trying to accomplish, just having a hard time making it reusable.
More details on what I have tried so far (haven't tried anything in the answers just yet).
I attempted to add a dependencyproperty that would expose the collection for the tabcontrol itemssource:
public IEnumerable<object> TabSource
{
get { return (IEnumerable<object>)GetValue(TabSourceProperty); }
set { base.SetValue(FunctionPanel.TabSourceProperty, value); }
}
public static DependencyProperty TabSourceProperty = DependencyProperty.Register(
"TabSource",
typeof(IEnumerable<object>),
typeof(FunctionPanel));
And then bind to it in the user control XAML:
<TabControl Grid.Row="1" ItemsSource="{Binding TabSource}" />
Finally, I would like to use it in the window XAML like so:
<local:FunctionPanel>
<local:FunctionPanel.TabSource>
<TabItem Header="Test" />
</local:FunctionPanel.TabSource>
</local:FunctionPanel>
But this returns TabSource is unrecognizable or unaccessible. I will attempt the solutions provided below.
My question is, how do I expose the tab control through the user control so we can add tabs?
One straight forward option would be adding a public method to the user control:
public void AddTab(string header)
{
this.tabControl.Items.Add(header);
}
another option would be to expose the Items property on the user control:
public ItemCollection Items
{
get { return this.tabControl.Items; }
}
I provide you with a sample to open a Page inside a Tab Control , hope it helps :
public void OpenTabForm(Page oPage)
{
try
{
Frame oFrame = new Frame();
oFrame.Content = oPage;
TabItem myItem = new TabItem();
myItem.Header = oPage.Name; //give the header text
myItem.Content = oFrame;
tbtabMain.Items.Add(myItem);
tbtabMain.SelectedItem = myItem;
}
catch (Exception ex)
{
//handle error
}
}

How can I modify the visual state of a disabled checkbox to look enabled?

I am designing a comparison dialog (shows several widgets with their characteristics in a grid). There is a features section where all available features are listed with a check box for each one. If the part has that feature, the checkbox is checked. These checkboxes need to be read-only so I've isEnabled=false. However visually the checkboxes (and the label content) show as greyed out.
Here are some important points:
The checkbox is a visual indicator of whether a part has a feature. There is no requirement for interaction.
The requirement is for a checkbox; I'd have to convince the powers that be to use something different.
What I want is an easy way to style/controltemplate a checkbox (and it's content) so it looks enabled, but doesn't react to user input.
Microsoft provides some of their default styles on MSDN and you can find the default style for a checkbox here: http://msdn.microsoft.com/en-us/library/ms752319(v=vs.85).aspx. Copy this style into your project, remove the Trigger for IsEnabled and set the style for your checkboxes to this new style.
On a side note, I'd recommend copying the style into a separate ResourceDictionary for reusablitiy and to keep the style from cluttering up your xaml files.
Create a custom control by inheriting from CheckBox, and in its constructor create a Click handler for it. Within that Click handler, put the following code:
((CheckBox)sender).Checked = !((CheckBox)sender).Checked;
Here's a complete example.
For Windows Forms:
namespace System.Windows.Forms
{
public class UnChangingCheckBox : System.Windows.Forms.CheckBox
{
public UnChangingCheckBox()
{
this.Click += new EventHandler(UnChangingCheckBox_Click);
}
void UnChangingCheckBox_Click(object sender, EventArgs e)
{
((CheckBox)sender).Checked = !((CheckBox)sender).Checked;
}
}
}
For WPF:
namespace System.Windows.Controls
{
public class UnchangingCheckBox : System.Windows.Controls.CheckBox
{
public UnchangingCheckBox()
{
this.Click += new System.Windows.RoutedEventHandler(UnchangingCheckBox_Click);
}
void UnchangingCheckBox_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (((CheckBox)sender).IsChecked.HasValue)
((CheckBox)sender).IsChecked = !((CheckBox)sender).IsChecked;
}
}
}
If you place the above code in a new class in your Windows Forms or WPF project, they'll appear as new tools in your toolbox. Then all you need to do is drag your new "UnchangingCheckBox" control onto your form where you were using a CheckBox. You don't need to do any coding on your form.
Using this approach your code will still be able to do everything you could do to a CheckBox (set its value, etc). It's only user interaction that's been disabled in a way that doesn't interfere with the visual style.
The solution suggested above works well for Windows Forms, but I see what you mean about WPF and the check mark appearing for a second.
Try this instead:
namespace System.Windows.Controls
{
public class UnchangingCheckbox : CheckBox
{
public UnchangingCheckbox()
{
this.IsReadOnly = true;
}
public bool IsReadOnly
{
get { return !this.IsHitTestVisible && !this.Focusable; }
set
{
this.IsHitTestVisible = !value;
this.Focusable = !value;
}
}
}
}
You acquire a property called "IsReadOnly", which by default is set to true, and has the behaviour you require without the annoying "checkmark appears for a second" behaviour.

choosing to hide or show tooltips based on bool

so I figured I'm making just a stupid mistake here. In the first of what will be many controls, I need to either show a balloon tooltip when a bool is true or not show them when the bool is false. I know that ShowAlways is not what I need to modify and I've tried various solutions already. Does anyone spot the problem? The bool is set by a checked dropdown item in a Help Menu Strip Item.
It will open with the application with the correct display, but as soon as I check that option to show it, it always shows there after.
public void changeBalloonProperties(bool boolSet)
{
ToolTip helpDeskInfoButtonToolTip = new ToolTip();
if (boolSet)
{
helpDeskInfoButtonToolTip.ToolTipTitle = "HelpDesk Information Button";
helpDeskInfoButtonToolTip.UseFading = true;
helpDeskInfoButtonToolTip.UseAnimation = true;
helpDeskInfoButtonToolTip.IsBalloon = true;
helpDeskInfoButtonToolTip.ShowAlways = true;
helpDeskInfoButtonToolTip.AutoPopDelay = 5000;
helpDeskInfoButtonToolTip.InitialDelay = 1000;
helpDeskInfoButtonToolTip.ReshowDelay = 500;
helpDeskInfoButtonToolTip.SetToolTip(helpDeskButton, "Click to launch HelpDesk user info page in default browser.");
}
else
{
helpDeskInfoButtonToolTip.RemoveAll();
}
}
You are creating a new ToolTip instance each time the changeBalloonProperties is called so the code isn't removing the caption associated with the original ToolTip that was used with the helpDeskButton. Try moving the ToolTip declaration outside of your changeBalloonProperties method so the same ToolTip object is used with RemoveAll().
Also note you can use that same ToolTip object to add captions for multiple controls (as shown in the sample here) and it's probably better to set helpDeskInfoButtonToolTip.Active = false to disable them all at once instead of setting and removing the captions (and other properties) each time you toggle.

Funky results when using UI Automation to get items in a ComboBox

We are using the code below to get a list of items out of a ComboBox inside another application's window. This code works (correctly retrieves the list of items) for ComboBoxes in any other application we've tested this code on, however for this particular application the Name property retrieved for each ListItem is garbled.
Here is the code:
using System.Windows.Automation;
var condition = new PropertyCondition(AutomationElement.NameProperty, "Change/Add/Delete Setting");
var condition2 = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window);
var condition3 = new AndCondition(new Condition[] {condition, condition2});
var window = AutomationElement.RootElement.FindFirst(TreeScope.Subtree, condition3);
condition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ComboBox);
var combo = window.FindFirst(TreeScope.Subtree, condition);
condition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem);
AutomationElementCollection children = combo.FindAll(TreeScope.Subtree, condition);
var comboItems = new List<string>();
foreach (AutomationElement child in children)
{
comboItems.Add(child.Current.Name);
}
And here is a screenshot of what we end up with for this one app.
What could cause the Name property to be garbled like this? Could this be an encoding problem?
How can we get the correct text for each item?
If this combobox has the CBS_OWNERDRAWFIXED or CBS_OWNERDRAWVARIABLE style, or the contained listbox has the LBS_OWNERDRAWFIXED or LBS_OWNERDRAWVARIABLE style. then the text isn't known by the control at all. When an app uses one of these styles, it gets WM_DRAWITEM messages whenever the control needs to draw, then it pulls the text from it's pocket and draws it wherever it was asked to.
This is a trick that allows an application to quickly and easily change the contents of a listbox or combobox on the fly, it's mostly used when the contents are volatile or when there are LOTS of items. It's one way to get around the limit on the number of items an listbox/combobox can hold.
Use Spy++ to check the styles on these windows.

Categories