WPF link button - wpf-controls

I have a button control to which I want add image as well as hyperlink property, i.e it should be an image button with link to other source. I tried
<Button Click="OnNavigationRequest" ToolTip="Orkut">
<Image Source="C:\Documents and Settings\SaurabhS\My Documents\Visual Studio 2008 \Projects\SaurabhSinhaDemos\WPF_Zone\AddressBook\AddressBook\images\orkut.jpeg"/>
<Hyperlink NavigateUri="http://www.orkut.com">Orkut</Hyperlink>
</Button>
and in code behind:
AddHandler(Hyperlink.RequestNavigateEvent,
new RoutedEventHandler(OnNavigationRequest));
public void OnNavigationRequest(object sender, RoutedEventArgs e)
{
var source = e.OriginalSource as Hyperlink;
if (source != null)
Process.Start(source.NavigateUri.ToString());
}
But got the following error:
content set more than once...
How should I do it?

In your code, the Button element contains two child elements. The Button element can only take one child element.
Wrap Image and Hyperlink in a StackPanel or some other layout container and the error will go away (see Int3's answer for an example).

Try following
<Button>
<StackPanel Orientation="Horizantal">
<Image Source="path to the image"/>
<Hyperlink NavigateUri="http://www.orkut.com"/>
</StackPanel>
</Button>

Related

Triggering function on Xamarin.Forms Entry Focused/Unfocused

Original problem: I want to call a function each time the soft keyboard is shown/hidden on my Xamarin.Forms ContentPage.
One option was to use a custom renderer where I have access to the keyboard observers. I haven't tried this yet; I thought I'd try banging my head with other approaches first.
Approach 1) Assign event handler to the Focused/Unfocused events of all entries on my page which trigger a keyboard show/hide, in the page's code-behind as follows:
EventHandler<FocusEventArgs> keyboard_handler = (object sender, FocusEventArgs e) =>
{
var binding_context = BindingContext as MyViewModel;
binding_context?.OnKeyboardShowing();
};
PasswordEntry.Focused += keyboard_handler; // doesn't trigger keyboard_handler
PasswordEntry.Unfocused += keyboard_handler; // doesn't trigger
UsernameEntry.Focused += keyboard_handler; // triggers
UsernameEntry.Unfocused += keyboard_handler; //doesn't trigger
Question 1: Why don't some of those trigger?
Approach 2) Use EventTriggers along with a custom TriggerAction<Entry> class, as follows:
Part of the XAML file showing one of the entries (which is in a grid, in a StackLayout in a ScrollView in a Grid, if you must know):
<Entry Grid.Row="0"
x:Name="UsernameEntry"
Margin="0,2"
HorizontalOptions="FillAndExpand"
Placeholder="User"
IsVisible="{Binding UsernameEnabled}"
Completed="Username_Completed"
IsEnabled="{Binding EnableControls}"
Text="{Binding Username, Mode=TwoWay}" >
<Entry.Triggers>
<EventTrigger Event="Focused">
<local:FocusedAction />
</EventTrigger>
</Entry.Triggers>
</Entry>
And the TriggerAction<Entry> class defined in the code-behind:
public class FocusedAction : TriggerAction<Entry>
{
protected override void Invoke(Entry entry)
{
Debug.WriteLine("Reached"); // Except it never reaches here.
}
}
Question 2: Why doesn't Invoke up there ever get triggered?
Am I missing something in my XAML, code-behind or somewhere else? I've checked the Xamarin docs, but as always, I've found them less than useless.

How to get the value of a cms:FormField in a form layout script block?

I have a form that has a layout like so:
<cms:FormField runat="server" ID="fMemberType" Field="MemberType" />
<cms:FormField runat="server" ID="fEmployeeCount" Field="EmployeeCount" />
<asp:Literal runat="server" ID="test" Text="test" />
<script runat="server">
protected void Page_PreRender(object sender, EventArgs e)
{
test.Text = fMemberType.Value.ToString();
}
</script>
However this produces Object reference not set to an instance of an object. because it can't find fMemberType for some reason. Looking for the correct way of doing this.
It's worth noting that the form fields are dropdowns with depending flags set so changing them triggers a postback, or at least it would, but I set the webpart container to be an update panel so it's AJAXing which means the data isn't available in the page POST params. I could turn this off and grab the data from the POST data but wanted to know if there was a better way first.
So you're fully defining the fields and everything for your form? Why not use the DataForm control and dynamically create the form for you? You can then get the data like so: (formUserSettings is a cms:DataForm)
EditingFormControl ctrState = formUserSettings.BasicForm.FieldEditingControls["UserState"] as EditingFormControl;
Then do some checking and assign the value:
if (ctrState != null)
{
fState = ctrlState.Value;
}
Most likely the form value is not set until after the pre-render. Alen Genzic's recommendation will show that. May want to try OnInit.

Add extra note field to grid line

I have a client that would like to add an extra note field to a grid. If this is not possible, is there a way to have a large text field in a grid that uses a pop up window for editing the large amount of text in that field?
Priority:
1.) Add extra note field to grid, if possible.
2.) Failing #1, is there a way to add a popup window to edit a large standard user text field.
I believe the answer to your number 1 question is no. If the grid already has a note it cannot have another. I had this question come up before.
For #2, you should be able to do a smart panel that displays your field. Use a PXTextEdit and setup a new view for the panel to point to based on your selected/current row.
To add a smart panel (pop up panel) you need a handful of things in place. I prefer using AEF with graph and table extensions. There is documentation in the T200/T300 training material for these topics. In my example I add the note ability to the sales order page. I copied most of the logic from the existing "PO Link" button and panel which is the POSupplyOK PXAction and the currentposupply view (page SO301000).
First you need your new field which we will add to the sales line as an extension table/field:
[PXTable(typeof(SOLine.orderType), typeof(SOLine.orderNbr), typeof(SOLine.lineNbr), IsOptional = true)]
public class SOLineExtension : PXCacheExtension<SOLine>
{
#region XXMyNote
public abstract class xXMyNote : PX.Data.IBqlField
{
}
protected string _XXMyNote;
[PXDBString]
[PXUIField(DisplayName = "My Note")]
public virtual string XXMyNote
{
get
{
return this._XXMyNote;
}
set
{
this._XXMyNote = value;
}
}
#endregion
}
Then we need to create a new graph extension to add the view for the panel and the PXAction for the button to open the panel.
public class SOOrderEntryExtension : PXGraphExtension<SOOrderEntry>
{
public PXSelect<SOLine,
Where<SOLine.orderType, Equal<Current<SOLine.orderType>>,
And<SOLine.orderNbr, Equal<Current<SOLine.orderNbr>>,
And<SOLine.lineNbr, Equal<Current<SOLine.lineNbr>>>>>> MyPanelView;
public PXAction<SOOrder> myNoteAction;
[PXUIField(DisplayName = "Add Note", MapViewRights = PXCacheRights.Select, MapEnableRights = PXCacheRights.Update)]
[PXButton(ImageKey = PX.Web.UI.Sprite.Main.DataEntryF)]
protected virtual IEnumerable MyNoteAction(PXAdapter adapter)
{
if (Base.Transactions.Current != null &&
MyPanelView.AskExt() == WebDialogResult.OK)
{
//extra stuff here if needed when OK is pushed
}
return adapter.Get();
}
}
now you need to "edit" the sales order page. you need to get your changes into a customization project and I usually go edit the page direct in visual studio under site\pages\so in this example. Then come back and paste in my code into the customization project by opening the project and performing the following steps:
Click on screens and the + sign to add a new screen
Enter SO301000 and save
Click on the SO301000 hyperlink to open the layout editor for sales order
Click Actions > Edit ASPX
Paste in your changes (mentioned below)
In the SO301000 page add the following:
[1] Add your DS Callback command within the PXDataSource tag
<px:PXDSCallbackCommand Name="MyNoteAction" Visible="False"
CommitChanges="true" DependOnGrid="grid" />
[2] Add the button to the toolbar above the sales line grid by adding the following to the PXGrid > ActionBar > CustomItems tags of the grid in the Document Details tab. (just search "PO Link" in the page to find this location easier or any of the listed buttons above the grid).
<px:PXToolBarButton Text="Add Note" DependOnGrid="grid">
<AutoCallBack Command="MyNoteAction" Target="ds" />
</px:PXToolBarButton>
[3] Add the panel code which represents what the panel will look like. You can play around with the sizing to fit your needs, just make sure you set your PXTextEdit to use MultiLine using the following example code. Look at the current sales order page to know where it fits into the page syntax:
<px:PXSmartPanel ID="PXSmartPanelNote" runat="server" Caption="My Note Panel Caption"
CaptionVisible="true" DesignView="Hidden" LoadOnDemand="true" Key="MyPanelView" CreateOnDemand="false" AutoCallBack-Enabled="true"
AutoCallBack-Target="formMyNote" AutoCallBack-Command="Refresh" CallBackMode-CommitChanges="True" CallBackMode-PostData="Page"
AcceptButtonID="btnMyNoteOk">
<px:PXFormView ID="formMyNote" runat="server" DataSourceID="ds" Style="z-index: 100" Width="100%" CaptionVisible="False"
DataMember="MyPanelView">
<ContentStyle BackColor="Transparent" BorderStyle="None" />
<Template>
<px:PXLayoutRule ID="PXLayoutRule44" runat="server" StartColumn="True" LabelsWidth="S" ControlSize="XM" />
<px:PXTextEdit ID="cstXXMyNote" runat="server" DataField="XXMyNote" TextMode="MultiLine"/>
</Template>
</px:PXFormView>
<px:PXPanel ID="PXPanel10" runat="server" SkinID="Buttons">
<px:PXButton ID="btnMyNoteOk" runat="server" DialogResult="OK" Text="OK"/>
</px:PXPanel>
</px:PXSmartPanel>
I have not fully tested the above but a quick slap together brought up the panel with no errors. I was using version 6.00.0955 but the same steps should work in all 5.X versions. Hope this helps.

WinRT XAML How to get current text of a textbox when using Win8nl EventToCommandBehaviour

I have been trying to figure this out for ages and I am stumped.
I have the following XAML:
<TextBox x:Name="MyTextBox" Text="{Binding MyName, Mode=TwoWay}" Width="200">
<WinRtBehaviors:Interaction.Behaviors>
<Win8nl_Behavior:EventToCommandBehavior Event="TextChanged"
Command="TextChangedCommand"
CommandParameter="{Binding Text, ElementName=MyTextBox, Mode=OneWay}"/>
</WinRtBehaviors:Interaction.Behaviors>
</TextBox>
And in my View Model:
public ICommand TextChangedCommand
{
get
{
return new RelayCommand<string>((p) =>
{
var msg = new MessageDialog(string.Format("Hi there {0}", p));
msg.ShowAsync();
});
}
}
But the string value I am hoping to appear in the CommanParameter (p) is always null.
What am I doing wrong?
The best thing you can do is to pass in the text value as the CommandParameter.
Behaviors are not part of the Visual Tree, so they don't have access to the XAML scope and the capability to perform ElementName bindings. This blog post provides more details, and a suitable solution.

WinRT Event Handling from DataTemplate

I have a DataTemplate which requires an event handler for one of the objects. This DataTemplate is contained in a ResourceDictionary. What is the best way to add an event handler to this template?
I tried defining the event handler in app.xaml.cs but the handler isn't executing. Creating a code behind file for the ResourceDictionary leads to load errors during app start up in MergedDictionaries.
from GraphStyles.xaml
<DataTemplate x:Key="PieTemplate">
<Grid HorizontalAlignment="Left" Width="350" Height="350" >
<Border>
<Charting:Chart
x:Name="PieChart"
Title="Play Attempts"
Margin="70,0" Loaded="PieChart_Loaded">
<Charting:Chart.Series>
<Charting:PieSeries
Title="Attempts"
ItemsSource="{Binding Items}"
IndependentValueBinding="{Binding Name}"
DependentValueBinding="{Binding Value}"
IsSelectionEnabled="True" />
</Charting:Chart.Series>
</Charting:Chart>
</Border>
</Grid>
</DataTemplate>
in App.Xaml.cs
private void PieChart_Loaded(object sender, RoutedEventArgs e)
{
var pieChart = sender as Chart;
var legendItems = ((PieSeries)pieChart.Series[0]).LegendItems;
foreach (LegendItem item in legendItems)
{
pieChart.LegendItems.Add(item);
pieChart.LegendStyle = item.Style;
}
}
Option 1
As far as I am aware you will have to reference the datatemplate in the page/usercontrol's Resources at the top. Use a merged dictionary so you can still utilize the graphstyles.xaml.
If you are uncomfortable as this breaks your convention, there is a rather long winded alternative:
Option 2
Use an MVVM Viewmodel and set the page/usercontrols DataContext.
Keep the datatemplate in the graphstyles.xaml and use an Attached Behavior to hook the Loaded event, passing the event trigger up to the viewmodels command.
Create an event in the ViewModel that the UI can respond to, then hook onto that and handle in the Views codebehind as you have done.
I must say I'm not mad on Option 2 as it kind of breaks some view/VM seperation but it should get the job done - note that you will have to pass the chart as an object through from the attached behavior, to the viewmodel then back to the view against before you cast it back to a Chart.

Resources