When I create (try to create) a ComboBox in WiX, the box receives its initial value from the corresponding property's value set earlier in the .wxs-file. This far, everythings goes as planned. When I try to change its value graphically, it displays no available list items. I have not found any necessary or relevant attributes etc in the docs that I haven't used, but also I'm quite noobish on WiX so maybe have missed something obvious. The code is below:
<Property Id="LANGUAGE" Value="Swedish" />
... cut ...
<Control Type="ComboBox" ComboList="yes" Property="LANGUAGE" Id="languages_combo" Width="..." Height="..." X="..." Y="...">
<ComboBox Property="LANGUAGE">
<ListItem Value="Swedish" />
<ListItem Value="English" />
</ComboBox>
</Control>
I want to be able to select "English" instead of "Swedish" in the drop-down, but that option is not available (and not "Swedish" for that matter - even that's the default value). Any suggestions how to solve this? I have searched the net without success, so I guess it's so basic no one has run into the same problem :-)
If it helps, here is the compilation:
candle test.wxs
light -ext WixUIExtension -sice:ICE20 test.wixobj
Attempts made by me:
Adding Text="..." to the ListItems does not help.
Replacing "ComboBox" with "ListBox" (and removeing attribute ComboList) displays the options/ListItems, but unfortunately ListBox is not the control that I want.
It's interesting when you make the same mistake over and over again, and never realize it's the good old mistake. I increased the Height attribute for Control, so the ListItems fit. Works like a charm!
I think you need to set the visible displayed text on the ListItems.
Try this:
<ComboBox Property="LANGUAGE">
<ListItem Text="English" Value="English" />
<ListItem Text="Swedish" Value="Swedish" />
</ComboBox>
Related
How do I set tab ordering in WPF? I have an ItemsControl with some items expanded and some collapsed and would like to skip the collapsed ones when I'm tabbing.
Any ideas?
If you want to explicitly set the tab ordering for elements in your form, the following attached property is supposed to help:
<Control KeyboardNavigation.TabIndex="0" ... />
I say "supposed to help" as I haven't found it very reliable though I probably need to read more about how it is intended to be used. I only post this half baked answer because no one else mentioned this property.
Note that in Win RT, the property is just TabIndex="0".
You can skip elements in the tab sequence by setting KeyboardNavigation.IsTabStop on the element in XAML.
KeyboardNavigation.IsTabStop="False"
You can setup a trigger that would toggle this property based on the expanded state.
<Control KeyboardNavigation.TabIndex="0" ... /> Works perfectly fine...
For example-
<ComboBox Height="23"
Margin="148,24,78,0"
Name="comboBoxDataSet"
VerticalAlignment="Top"
SelectionChanged="comboBoxDestMarketDataSet_SelectionChanged"
DropDownOpened="comboBoxDestMarketDataSet_DropDownOpened"
KeyboardNavigation.TabIndex="0" />
<ComboBox Height="23"
Margin="148,56,78,0"
Name="comboBoxCategory"
VerticalAlignment="Top"
SelectionChanged="comboBoxDestCategory_SelectionChanged"
DropDownOpened="comboBoxDestCategory_DropDownOpened"
KeyboardNavigation.TabIndex="1" />
Will allow you to navigate through these two combo boxes using TAB key.
I think there is a much easier solution here,
at the top within your control or window or whatever, you could add:
KeyboardNavigation.TabNavigation="Cycle"
This also automaticaly ignores the collapsed tabs.
Another alternative that has worked for me in the past is to simply remove all explicit TabIndex statements, and let the controls use the order that they're declared in XAML work their magic.
This, of course, may require you to reorder your controls. But this is a simple copy-paste operation.
You can use KeyboardNavigation.TabNavigation="None" to completely skip the Tabbing for specific control.
I'm looking to create a UI element in a WPF XAML UserControl with something that looks and works roughly like Google Suggest - a TextBox with a ListBox that appears beneath it showing suggestions that match the text entered in the TextBox. In simplified form, my XAML looks like this:
<StackPanel>
[...controls above...]
<TextBox ... />
<ListBox ItemsSource="{Binding SearchHints}"
Visibility="{Binding HasSearchHints}" MaxHeight="100" />
[...controls below...]
</StackPanel>
What I'm struggling to achieve is I want the ListBox to float above any content that may come below it, much like the dropdown part of a ComboBox does. Currently it pushes any controls below it downwards. I figure this must be possible because the ComboBox control essentially does exactly what I want to do. In CSS it would be a matter of setting the element to position:relative but there doesn't seem to be an immediately obvious equivalent in XAML. Any ideas?
Used Icepickle's comment - the element did exactly what I wanted.
In one of my dialogs, I have the following control:
<Control Id="EnvironmentComboBox" Type="ComboBox" Sorted="yes" ComboList="yes" Property="ENVIRONMENT" X="25" Y="110" Width="200" Height="15" />
I fill the ComboBox in elsewhere like so:
<UI>
<ComboBox Property="ENVIRONMENT">
<ListItem Text="Development" Value="Development" />
<ListItem Text="SIT" Value="SIT" />
<ListItem Text="UAT" Value="UAT" />
<ListItem Text="Production" Value="Production" />
</ComboBox>
</UI>
However, if I don't have the ComboBox bit created, the MSI will still build, and it will fail during install (2205). Thus, I would like to enforce the requirement to have a property named ENVIRONMENT. I've tried adding a PropertyRef like below to my dialog:
<PropertyRef Id="ENVIRONMENT" />
However, this doesn't seem to pick up the <ComboBox Proeprty="ENVIRONMENT">. It will pick up a regular property (<Property Id="ENVIRONMENT" Value="test" />), but that doesn't really help much.
Is there any way to require a ComboBox to be defined?
EDIT: For clarification, I intend to keep the ComboBox definition separate from the Control definition so that the dialog can be reused.
MSI can exist without Combobox items declared for the property, referenced by a element (you have the ability to type any text you need in the combobox text field in case ComboList='no').
*The element doesn't have any corresponding object in the MSI tables* (only it's child elements gets written to the MSI's ComboBox table). So I suppose this element is completely optional from WIX point.
Your error #2205 is caused by non-existance of the 'ComboBox' table at all. I suppose you have only one combobox in the installer. Theoretically it is impossible possible to detect this at compile-time as error (tables can be created in custom actions as well). The most WIX team can do is generate warning.
To avoid this error I declared a dummy combobox element in my reusable project:
<Fragment><!--This fragment is intended to fill MSI tables with dummy items so that these tables became created. Tables without items aren't created-->
<UI Id="Dummy">
<Dialog Id="DummyDlg" Width="370" Height="270" Title="Dummy" NoMinimize="yes">
<Control Id="DummyDlgComboBox" Type="ComboBox" Property="DummyComboboxProperty" Width="200" Height="17" X="100" Y="80">
<ComboBox Property="DummyComboboxProperty">
<ListItem Text="Dummy" Value="Dummy" />
</ComboBox>
</Control>
</Dialog>
</UI>
</Fragment>
and referenced this UI from my commonly-used UI sequences.
Now I don't need to worry about existance of the combobox table in any of my installers.
As for a workaround to your problem - how to enforce users not to forget to declare list items, I would do a tepmlate wix file instead of the wixlib. Something like this:
<Control Id="EnvironmentComboBox" Type="ComboBox" Sorted="yes" ComboList="yes" Property="ENVIRONMENT" X="25" Y="110" Width="200" Height="15">
<ComboBox Property="ENVIRONMENT">
<Placeholder Id="EnvironmentComboBoxItems" />
</ComboBox>
</Combobox>
and give users the only ability to reuse this code using template transformation tool you provide. It will validate if all template placeholders are provided with content.
The transformation may look like this:
<TemplateSubstitutions>
<PlaceholderContent PlaceholderId='EnvironmentComboBoxItems'>
<ListItem Text="Development" Value="Development" />
<ListItem Text="SIT" Value="SIT" />
<ListItem Text="UAT" Value="UAT" />
<ListItem Text="Production" Value="Production" />
</PlaceholderContent>
</TemplateSubstitutions>
The tool for merging them:
static void Main(string[] args)
{
var templatePath = args[0];
var templateTransformPath = args[1];
var resultPath = args[2];
var templateDoc = XDocument.Load(templatePath);
var transformationDoc = XDocument.Parse(templateTransformPath);
Dictionary<string, XElement> contents = transformationDoc.Element("TemplateSubstitutions").Elements("PlaceholderContent").ToDictionary(e => e.Attribute("PlaceholderId").Value, e => e);
var planceHolders = templateDoc.Descendants("Placeholder").ToArray();
foreach (var ph in planceHolders)
{
ph.ReplaceWith(new XElement(contents[ph.Attribute("Id").Value]).Nodes());
}
templateDoc.Save(resultPath);
}
Of course this tool isn't release yet - you may want to add some meaningful error messages to your clients and validation of provided transformations. But to avoid code complication I didn't implement that.
I use this approach in few installer projects I have currently. All templates are stored in the common location and client installers can take any file they need and transform it.
My release tool is a bit more advanced of course. It can substitute values in the attributes using wildcards - I consider it extreemely useful when reusing components. I use then template like this:
<Component Guid="{StrToGuid({ProductName}_7A51C3FD-CBE9-4EB1-8739-A8F45D46DCF5)}">
and user should provide all template properties (such as 'ProductName') in command-line of my template transformation tool. It ensures components will have unique GUIDs between different products, so they will not conflict when installed on the same machine.
NOTE: Be careful with figure brackets though - they have special meaning for WIX and MSI: http://msdn.microsoft.com/library/aa368609.aspx. But as for me it is not clear enough and I don't use them regularly. But you might need another wildcard prefix.
As for organizing the installer build process, you can add template transformation calls on pre-build of the project. But I decided to use separate build scripts instead of native Visual studio build. It looks much more simple and flexible. And I don't get nasty errors like "command 'xxx' exited with code yyy" - I always see the template transformation log, error messages etc.
Hope my reinvention of the wheel will help anybody =).
I suspect <PropertyRef> was designed the way to pick up only the "direct" definitions of properties, that is, <Property> elements. The <ComboBox> just mentions the property name in its attribute, and this is not treated as a property definition.
Add a "direct" property definition to your sample, and it should work:
<UI>
<Property Name="ENVIRONMENT" Value="" />
<ComboBox Property="ENVIRONMENT">
<ListItem Text="Development" Value="Development" />
<ListItem Text="SIT" Value="SIT" />
<ListItem Text="UAT" Value="UAT" />
<ListItem Text="Production" Value="Production" />
</ComboBox>
</UI>
And reference it with <PropertyRef> element in another place - just the way you tried.
As far as I know, such a definition won't harm the combobox part, and you'll be on the safe side with proper fragment inclusion.
Alternatively, you can reference the entire <UI> element with <UIRef> element - it should have the same effect.
Why not define your combobox inside the element? Like this:
<Control Id="EnvironmentComboBox" Type="ComboBox" Sorted="yes" ComboList="yes" Property="ENVIRONMENT" X="25" Y="110" Width="200" Height="15">
<ComboBox Property="ENVIRONMENT">
<ListItem Text="Development" Value="Development" />
<ListItem Text="SIT" Value="SIT" />
<ListItem Text="UAT" Value="UAT" />
<ListItem Text="Production" Value="Production" />
</ComboBox>
</Combobox>
In this case you won't be able to reference dialog not referencing the combobox. Maybe I understood you wrong, but it looks logically to avoid user errors rather than throwing them.
If your user needs to be able to change list items of your library-dialog, you can populate dialog items with custom action for example (though it is probably not the best approach in case of static values).
I also faced plenty of problems with reusing WIX elements and ended up with creating own template project and using some transformation of wxs files (for now quite simple, but can implement anything I need) for every installer I create. Works great and gives infinite flexibility.
first of all I would like to thank you for the many good posts that i read in this forum. Unluckily I could not find anything of help for my current problem (either here or anywhere else).
What I'm trying to do sounds quite simple, but I have no clue how to get it to work ... perhaps I'm still to new to wpf or I don't thing wpfy enough :)
I'm designing a front end for a part in an automated manufacturing:
I have a quantity of places where pallets can be put (but it can be empty as well).
Each pallet has up to 3 places where parts can be mounted
Everything is created dynamically of a database and is reacting to changes.
The position of the parts on the pallet comes from the database as well and should be visualized
What I would like to have is:
An overview over the pallet-places with a preview of the pallet
When I select a place I want to see a detail view of the place
When I click on a part on the pallet of the detailed pallet I want to see details to the part
The first two points are quite simple and work nicely:
I have got a DataTemplate for every component (part, pallet, pallet-place). Actually those are UserControls that are imported as Datatemplates
the overview is a ListBox with the places as DataContext
for the detail-place-view I use the UserControl and bound it to the SelectedItem of the Listbox
I tried to bind the Text of a Textblock to the ID of the selected Part ... and fail.
Probably I could use some global variables in the code behind - but that sound very ugly.
Can anybody help?
I have got a solution ... it is not nice but works.
I created an event in the pallet, that triggers, when the selected part-place changes
I handle the event in the pallet-place and create a new one
And finally I handle it in the overview and change the detailview accordingly
Most likely there are much nicer solutions, but it will suffice.
Perhaps try an ElementName binding?
<TextBlock Text="{Binding ElementName=Name_of_your_Listbox, Path=SelectedItem.ID" />
Can you post a bit more code of your TextBlock and your Binding?
Context is important, if i use a ContentControl and bind its content to the SelectedItem like this:
<ContentControl Content="{Binding SelectedItem, ElementName=mylistbox}">
I can bind to the ID of the selected item in the DataTemplate like this:
<ContentControl.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding ID}" />
</DataTemplate>
</ContentControl.ContentTemplate>
That is because setting the Content of the ContentControl automatically sets the DataContext as well, and this binding is relative to the DataContext since no source (ElementName, RelativeSource, Source) has been specified.
I do not know how your UserControl handles the context, if the DataContext is not affected such bindings will not work. You would need to bind directly then:
<uc:MyDetailsView Data="{Binding SelectedItem, ElementName=mylistbox}">
<!-- ... -->
<TextBlock Text="{Binding SelectedItem.ID, ElementName=mylistbox}" />
This of course defeats the purpose of having the binding on the UserControl itself in the first place. But unless you post some relevant code it's quite hard to tell what is wrong.
Also check the Output window in VisualStudio, binding errors will show up there and might provide valuable information as to what went wrong.
I haven't used WPF that much so the solution to this is probably pretty easy.
In the ide I'm developing it will have multiple controls(text editor) each being hosted in a tab, much like VS does for each source file. When the user clicks new the "host" creates a new EditorWindow(a usercontrol), creates a new tab, and tells the tab to display the EditorWindow it created, and then updates a property called currentWindow (of type EditorWindow) with the one that's currently active. Inside the EditorWindow is the text editor whose name is textEditor(also a property). What I'm trying to do is take this code from the quick start source of the text editor control I'm using
<StackPanel>
<CheckBox Checked="EditiorOptionsChecked" IsChecked="{Binding ElementName=Control, Path=currentWindow.textEditor.IsIndicatorMarginVisible}" Content="Indicator margin visible" />
<CheckBox Checked="EditiorOptionsChecked" IsChecked="{Binding ElementName=Control, Path=currentWindow.textEditor.IsLineNumberMarginVisible}" Content="Line number margin visible" />
<CheckBox Checked="EditiorOptionsChecked" IsChecked="{Binding ElementName=Control, Path=currentWindow.textEditor.IsRulerMarginVisible}" Content="Ruler margin visible (useful for fixed-width fonts only)" />
<CheckBox Checked="EditiorOptionsChecked" IsChecked="{Binding ElementName=Control, Path=currentWindow.textEditor.IsSelectionMarginVisible}" Content="Selection margin visible" />
</StackPanel>
put that in the host controls xaml, and bind the checkboxes to the syntax editor. I've tried a couple different things to no avail. Control is the name of the window hosting all the tabs, and path is obviously supposed to be the property that the checkboxes are bound too. I'm pretty sure the problem is that at initial run-time currentWindow isn't initialized so therefore my bindings aren't ever getting updated, but I'm at a loss as to how to fix this issue. Thanks!
Since you are new to WPF, you may not know that properties have to implement some sort of change notifications in order for bindings to work. For instance, if any of the properties in the the path "currentWindow.textEditor.IsIndicatorMarginVisible" change, you need to inform the binding engine that it has changed. If you implement these properties as DependencyPropertys, the change tracking comes for free. Otherwise, you should implement INotifyPropertyChanged.
I've found that the Snoop utility is the easiest way to do quick binding debugging, you should try using it and see if it tells you anything useful on the bound properties.