I implemented this CustomStepper:
using System;
using Xamarin.Forms;
namespace AppXamarin
{
public class CustomStepper : StackLayout
{
Button PlusBtn;
Button MinusBtn;
Entry Entry;
public static readonly BindableProperty TextProperty =
BindableProperty.Create(
propertyName: "Text",
returnType: typeof(int),
declaringType: typeof(CustomStepper),
defaultValue: 0,
defaultBindingMode: BindingMode.TwoWay);
public int Text
{
get { return (int)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public CustomStepper()
{
PlusBtn = new Button { WidthRequest = 30, HeightRequest = 30 };
MinusBtn = new Button { WidthRequest = 30, HeightRequest = 30 };
PlusBtn.Image = "exp20181029Artboard51";
MinusBtn.Image = "exp20181029Artboard52";
switch (Device.RuntimePlatform)
{
case Device.UWP:
case Device.Android:
{
PlusBtn.BackgroundColor = Color.Transparent;
MinusBtn.BackgroundColor = Color.Transparent;
break;
}
case Device.iOS:
{
PlusBtn.BackgroundColor = Color.Transparent;
MinusBtn.BackgroundColor = Color.Transparent;
break;
}
}
Orientation = StackOrientation.Horizontal;
PlusBtn.Clicked += PlusBtn_Clicked;
MinusBtn.Clicked += MinusBtn_Clicked;
Entry = new Entry { PlaceholderColor = Color.Gray, Keyboard = Keyboard.Numeric, WidthRequest = 30, BackgroundColor = Color.Transparent, FontSize = 15 };
Entry.Keyboard = Keyboard.Numeric;
Entry.Behaviors.Add(new NumericValidationBehavior());
Entry.SetBinding(Entry.TextProperty, new Binding(nameof(Text), BindingMode.TwoWay, source: this));
Entry.HorizontalTextAlignment = TextAlignment.Center;
Entry.TextChanged += Entry_TextChanged;
Children.Add(MinusBtn);
Children.Add(Entry);
Children.Add(PlusBtn);
}
private void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
if (!string.IsNullOrEmpty(e.NewTextValue) && e.NewTextValue != ".")
this.Text = int.Parse(e.NewTextValue);
}
private void MinusBtn_Clicked(object sender, EventArgs e)
{
if (Text > 0)
Text--;
}
private void PlusBtn_Clicked(object sender, EventArgs e)
{
Text++;
}
}
}
When placing normally in the page I can access it and take the text property and use it in my Xaml.cs code. But in my case, I'm placing it inside a listview and as you know in listview the items are bindable I can't access it directly. In the regular stepper when it is placed in the listview we can use the "ValueChanged" method and can easily get the value by using e.NewValue in the "ValueChanged" method in the Xaml.cs file. Is there a way that I can add something to the CustomStepper class that can help me access the Text property and uses it in the Xaml.cs file? Thanks in advance
You can create a property for EventHandlers. In this case, you would use the event modifier on the property to tell the program that the property is triggering an event. For example:
private EventHandler onValueChangedEvent = null;
public event EventHandler OnValueChanged
{
add
{
onValueChangedEvent = null;
onValueChangedEvent = value;
}
remove
{
// Will show a warning. You can ignore it.
onValueChangedEvent = null;
}
}
private void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
if (!string.IsNullOrEmpty(e.NewTextValue) && e.NewTextValue != ".")
this.Text = int.Parse(e.NewTextValue);
onValueChangedEvent?.Invoke(this, e);
}
You would then bind/assign an event handler in your xaml.cs code to the OnValueChanged property, which will get triggered when the value changes.
Related
I have an Xamarin.Forms app that supports many languages. How do I show the Calender for the DatePicker with DatePicker Ok and Cancel button text in local language text from resource file?
My custom renderer
[assembly: ExportRenderer(typeof(CustomImageDatePicker), typeof(CustomImageDatePickerRenderer))]
namespace AMS.Droid.Renderers
{
public class CustomImageDatePickerRenderer : DatePickerRenderer
{
public CustomImageDatePickerRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
try
{
base.OnElementChanged(e);
CustomImageDatePicker element = (CustomImageDatePicker)this.Element;
if (Control == null)
return;
Control.Background = null;
if (Control != null && this.Element != null && !string.IsNullOrEmpty(element.Image))
{
Control.Background = AddPickerStyles(element.Image);
}
}
catch (Exception ex)
{
var message = ex.Message;
}
}
public LayerDrawable AddPickerStyles(string imagePath)
{
GradientDrawable gd = new GradientDrawable();
gd.SetColor(Android.Graphics.Color.Transparent);
gd.SetCornerRadius(25);
gd.SetStroke(3, Android.Graphics.Color.Black);
this.Control.SetBackgroundColor(Android.Graphics.Color.Transparent);
this.Control.SetPadding(20, 10, -50, 10);
Drawable[] layers = { gd, GetDrawable(imagePath) };
LayerDrawable layerDrawable = new LayerDrawable(layers);
layerDrawable.SetLayerInset(1, 0, 0, 30, 0);
return layerDrawable;
}
private BitmapDrawable GetDrawable(string imagePath)
{
try
{
int resID = Resources.GetIdentifier(imagePath.ToLower(), "drawable", this.Context.PackageName);
var drawable = ContextCompat.GetDrawable(this.Context, Resource.Drawable.brandIcon);
drawable.SetBounds(0, 0, (int)(drawable.IntrinsicWidth * 0.5),
(int)(drawable.IntrinsicHeight * 0.5));
var bitmap = ((BitmapDrawable)drawable).Bitmap;
var result = new BitmapDrawable(Resources, Bitmap.CreateScaledBitmap(bitmap, 60, 60, true));
result.Gravity = Android.Views.GravityFlags.Right;
//result.SetBounds(10, 10, 50, 0);
return result;
}
catch(Exception ex)
{
var message = ex.Message;
}
return null;
}`
Xaml:
<customDatePicker:CustomDatePicker
x:Name="dpFromDate"
DateSelected="FromDate_Selected"
Margin="10,5,10,0"
Image="brandIcon.png"/>
You could do this with custom renderer.
On Android, the DatePicker dialog can be customized by overriding the CreateDatePickerDialog method in a custom renderer.
[assembly: ExportRenderer(typeof(Xamarin.Forms.DatePicker), typeof(CustomDatePickerRenderer))]
namespace App10.Droid
{
public class CustomDatePickerRenderer : DatePickerRenderer
{
public CustomDatePickerRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.DatePicker> e)
{
base.OnElementChanged(e);
//Disposing
if (e.OldElement != null)
{
datePicker = null;
}
//Creating
if (e.NewElement != null)
{
datePicker = e.NewElement;
}
}
DatePickerDialog pickerDialog;
private Xamarin.Forms.DatePicker datePicker;
protected override DatePickerDialog CreateDatePickerDialog(int year, int month, int day)
{
pickerDialog = new DatePickerDialog(Context, (o, e) =>
{
datePicker.Date = e.Date;
((IElementController)datePicker).SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, false);
}, year, month, day);
//ok
pickerDialog.SetButton((int)DialogButtonType.Positive, "(FR)-DONE", OnDone);
//cancel
pickerDialog.SetButton((int)DialogButtonType.Negative, "(FR)-CLEAR", OnCancel);
return pickerDialog;
}
private void OnCancel(object sender, DialogClickEventArgs e)
{
datePicker.Unfocus();
}
private void OnDone(object sender, DialogClickEventArgs e)
{
datePicker.Date = ((DatePickerDialog)sender).DatePicker.DateTime;
datePicker.Unfocus();
}
}
}
You could replace the (FR)-DONE and (FR)-CLEAR with your own local language text from resource file
//ok
pickerDialog.SetButton((int)DialogButtonType.Positive, "(FR)-DONE", OnDone);
//cancel
pickerDialog.SetButton((int)DialogButtonType.Negative, "(FR)-CLEAR", OnCancel);
How to add the Title "State" in the middle of the ToolBar for the PickerRenderer in Xamarin ios(Forms) ?
You could check the following code
using System;
using xxx.iOS;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(Picker), typeof(MyiOSPickerRenderer))]
namespace xxx.iOS
{
public class MyiOSPickerRenderer : PickerRenderer, IUIPickerViewDelegate, IUIPickerViewDataSource
{
string SelectedValue;
public MyiOSPickerRenderer()
{
}
public nint GetComponentCount(UIPickerView pickerView)
{
return 1;
}
public nint GetRowsInComponent(UIPickerView pickerView, nint component)
{
return Element.Items.Count;
}
[Export("pickerView:viewForRow:forComponent:reusingView:")]
public UIView GetView(UIPickerView pickerView, nint row, nint component, UIView view)
{
UILabel label = new UILabel
{
//here you can set the style of item!!!
TextColor = UIColor.Blue,
Text = Element.Items[(int)row].ToString(),
TextAlignment = UITextAlignment.Center,
};
return label;
}
[Export("pickerView:didSelectRow:inComponent:")]
public void Selected(UIPickerView pickerView, nint row, nint component)
{
Control.Text = Element.Items[(int)row];
SelectedValue = Element.Items[(int)row];
}
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (Control != null)
{
SelectedValue = Element.Items[0];
UIPickerView pickerView = (UIPickerView)Control.InputView;
pickerView.WeakDelegate = this;
pickerView.DataSource = this;
UIToolbar toolbar = (UIToolbar)Control.InputAccessoryView;
UIBarButtonItem save = new UIBarButtonItem("Save", UIBarButtonItemStyle.Done, (object sender, EventArgs click) =>
{
Control.Text = SelectedValue;
toolbar.RemoveFromSuperview();
pickerView.RemoveFromSuperview();
Control.ResignFirstResponder();
});
UIBarButtonItem Title = new UIBarButtonItem("States", UIBarButtonItemStyle.Done, null);
UIBarButtonItem cancel = new UIBarButtonItem("Cancel", UIBarButtonItemStyle.Bordered, (object sender, EventArgs click) =>
{
toolbar.RemoveFromSuperview();
pickerView.RemoveFromSuperview();
Control.ResignFirstResponder();
});
UIBarButtonItem empty = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace, null);
toolbar.Items = new UIBarButtonItem[] { cancel, empty, Title, empty, save };
}
}
}
}
I use Reflection to set the Label.TextProperty.CoerceValue to my custom delegate (TextProperty.CoerceValue are null by default)
but when Label text changed, the delegate are not called
the same strategy are apply/tried on Image.SourceProperty, Entry.TextProperty
all are called successful
is bug or Label.TextProperty by design will not call CoerceValue delegate?
thank you very much.
Xamarin.Forms 4.3.0.947036
var property = Label.TextProperty;
var coerceValue = property.GetType().GetProperty("CoerceValue", BindingFlags.NonPublic | BindingFlags.Instance);
oldDelegate = coerceValue?.GetValue(property) as BindableProperty.CoerceValueDelegate;
coerceValue?.SetValue(property, (bindable, value) => {
var modified = ModifyValue(value); // simply modify the value if required
return modified
});
If you want to call CoerceValue when Label.Text changed, I suggest you can use Bindable Properties to bind Label.TextPrperty.
public partial class Page9 : ContentPage
{
public static readonly BindableProperty labelvalueProperty = BindableProperty.Create("labelvalue", typeof(string), typeof(Page9), null , coerceValue: CoerceValue);
public string labelvalue
{
get { return (string)GetValue(labelvalueProperty); }
set { SetValue(labelvalueProperty, value); }
}
private static object CoerceValue(BindableObject bindable, object value)
{
string str = (string)value;
if(str=="cherry")
{
str = "hello world!";
}
return str;
}
public Page9 ()
{
InitializeComponent ();
label1.SetBinding(Label.TextProperty, "labelvalue");
labelvalue = "this is test";
BindingContext = this;
}
private void Btn1_Clicked(object sender, EventArgs e)
{
labelvalue = "cherry";
}
}
You can see the CoerceValue can be fired when Label.Text property changed.
I created a new Page Page1 in a Xamarin.Forms Project, with the following simple code in the code behind:
public Page1()
{
InitializeComponent();
}
protected override void OnAppearing()
{
Label l = new Label();
BindableProperty.CoerceValueDelegate d = (s, a) =>
{
string modified = "textY"; // simply modify the value if required
return modified;
};
var property = Label.TextProperty;
var coerceValue = property.GetType().GetProperty("CoerceValue", BindingFlags.NonPublic | BindingFlags.Instance);
var oldDelegate = coerceValue?.GetValue(property) as BindableProperty.CoerceValueDelegate;
coerceValue?.SetValue(property, d);
l.Text = "1"; // Text property is set to textY thanks to CoerceValueDelegate!
base.OnAppearing();
}
when i call l.Text = "1" the BindableProperty.CoerceValueDelegate i defined is correctly called, and l.Text is set to textY as expected.
#codetale, are you able to run this code on your side?
I am trying to make a custom stepper to use in my listview such as this one
Any idea how to do this? Thanks.
Solution 1:
A Stepper allows inputting a discrete value that is constrained to a range. You could display the value of the Stepper using data binding in a label as follows :
Define in XAML:
<StackLayout x:Name="Container">
<Label BindingContext="{x:Reference stepper}" Text="{Binding Value}" />
<Stepper Minimum="0" Maximum="10" x:Name="stepper" Increment="0.5" />
</StackLayout>
Solution 2:
You could create a BindableProperty to implement this function, for example:
public class CustomStepper : StackLayout
{
Button PlusBtn;
Button MinusBtn;
Entry Entry;
public static readonly BindableProperty TextProperty =
BindableProperty.Create(
propertyName: "Text",
returnType: typeof(int),
declaringType: typeof(CustomStepper),
defaultValue: 1,
defaultBindingMode: BindingMode.TwoWay);
public int Text
{
get { return (int)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public CustomStepper()
{
PlusBtn = new Button { Text = "+", WidthRequest = 40, FontAttributes = FontAttributes.Bold, FontSize = 15 };
MinusBtn = new Button { Text = "-", WidthRequest = 40, FontAttributes = FontAttributes.Bold, FontSize = 15 };
switch (Device.RuntimePlatform)
{
case Device.UWP:
case Device.Android:
{
PlusBtn.BackgroundColor = Color.Transparent;
MinusBtn.BackgroundColor = Color.Transparent;
break;
}
case Device.iOS:
{
PlusBtn.BackgroundColor = Color.DarkGray;
MinusBtn.BackgroundColor = Color.DarkGray;
break;
}
}
Orientation = StackOrientation.Horizontal;
PlusBtn.Clicked += PlusBtn_Clicked;
MinusBtn.Clicked += MinusBtn_Clicked;
Entry = new Entry
{
PlaceholderColor = Color.Gray,
Keyboard = Keyboard.Numeric,
WidthRequest = 40, BackgroundColor = Color.FromHex("#3FFF")
};
Entry.SetBinding(Entry.TextProperty, new Binding(nameof(Text), BindingMode.TwoWay, source: this));
Entry.TextChanged += Entry_TextChanged;
Children.Add(PlusBtn);
Children.Add(Entry);
Children.Add(MinusBtn);
}
private void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
if (!string.IsNullOrEmpty(e.NewTextValue))
this.Text = int.Parse(e.NewTextValue);
}
private void MinusBtn_Clicked(object sender, EventArgs e)
{
if (Text > 1)
Text--;
}
private void PlusBtn_Clicked(object sender, EventArgs e)
{
Text++;
}
}
For more detailed information, please refer to the following documents:
Stepper in Xamarin Forms
Stepper Control In Xamarin.Forms Application For Android And UWP
C# (CSharp) Xamarin.Forms.Stepper Code Examples
Xamarin Forms Guide -- Stepper
Update:
In the CustomStepper class, the Entry value is binding with the Text property, so you could get the value of the entry via customStepper.Text.
For example:
<local:CustomStepper x:Name="MyCustomerStepper"/>
You could get its Entry value in your xaml.cs file via:
var yourCustomerStepperEntryValue = MyCustomerStepper.Text.ToString();
I'm trying to write a webpart that basically pulls data from a list and displays it to the user. There is a feature news list where one of the columns holds a URL to an image. The web part should get the 3 most recent feature news items and create three image controls on the page. These image controls can be scrolled through by clicking on the buttons 1,2,3. (Ie, clicking on 2 will set the Visible property of image 1 and image 3 to false).
I have managed to implement AJAX here, but am now trying to use the UpdatePanelAnimationExtender from the AJAX Control Toolkit.
I have followed all instructions on how to use the toolkit, add it to the GAC, add a safe assembly, etc, and have gotten past all the errors besides this one:
"Page cannot be null. Please ensure that this operation is being performed in the context of an ASP.NET request"
My complete code below:
using System; using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.WebControls;
using System.Web.Extensions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System.ComponentModel;
using AjaxControlToolkit;
namespace FeatureNewsWebpartFeature {
[Guid("7ad4b959-d494-4e85-b164-4e4231692b8b")]
public class FeatureNewsWebPart : Microsoft.SharePoint.WebPartPages.WebPart
{
private bool _error = false;
private string _listName = null;
private string _imageColumn = null;
Image image1;
Image image2;
Image image3;
UpdatePanelAnimationExtender upAnimator;
[Personalizable(PersonalizationScope.Shared)]
[WebBrowsable(true)]
[System.ComponentModel.Category("List Connection Settings")]
[WebDisplayName("List Name")]
[WebDescription("Enter the name of the news list")]
public string ListName
{
get
{
if (_listName == null)
{
_listName = "News";
}
return _listName;
}
set { _listName = value; }
}
[Personalizable(PersonalizationScope.Shared)]
[WebBrowsable(true)]
[System.ComponentModel.Category("List Connection Settings")]
[WebDisplayName("Image Column Name")]
[WebDescription("Enter the column name of the ArtfulBits Image Upload column")]
public string ImageUrlColumn
{
get
{
if (_imageColumn == null)
{
_imageColumn = "Feature Image";
}
return _imageColumn;
}
set { _imageColumn = value; }
}
public FeatureNewsWebPart()
{
this.ExportMode = WebPartExportMode.All;
}
/// <summary>
/// Create all your controls here for rendering.
/// Try to avoid using the RenderWebPart() method.
/// </summary>
protected override void CreateChildControls()
{
if (!_error)
{
try
{
base.CreateChildControls();
//Create script manager
if (ToolkitScriptManager.GetCurrent(this.Page) == null)
{
ToolkitScriptManager scriptHandler = new ToolkitScriptManager();
scriptHandler.ID = "scriptHandler";
scriptHandler.EnablePartialRendering = true;
this.Controls.Add(scriptHandler);
}
//Create update panel
System.Web.UI.UpdatePanel imageUpdatePanel = new System.Web.UI.UpdatePanel();
imageUpdatePanel.ID = "imageUpdatePanel";
imageUpdatePanel.UpdateMode = UpdatePanelUpdateMode.Conditional;
this.Controls.Add(new LiteralControl("<div id=\"updateContainer\">"));
this.Controls.Add(imageUpdatePanel);
this.Controls.Add(new LiteralControl("</div>"));
//Make SPSite object and retrieve the three most recent feature news items
SPSite site = SPContext.Current.Site;
using (SPWeb web = site.OpenWeb())
{
SPList oList = web.Lists[ListName];
SPQuery oQuery = new SPQuery();
oQuery.RowLimit = 3;
oQuery.Query = "<OrderBy>" +
"<FieldRef Name='Modified' Ascending='False' /></OrderBy>" +
"<Where>" +
"<Eq>" +
"<FieldRef Name='ContentType' />" +
"<Value Type='Choice'>Feature News Item</Value>" +
"</Eq>" +
"</Where>";
oQuery.ViewFields = string.Concat(
"<FieldRef Name='Feature_x0020_Image' />" +
"<FieldRef Name='Feature_x0020_Order' />");
image1 = new Image();
image2 = new Image();
image3 = new Image();
//For each item, extract image URL and assign to image object
SPListItemCollection items = oList.GetItems(oQuery);
foreach (SPListItem oListItem in items)
{
string url = oListItem["Feature_x0020_Image"].ToString();
url = url.Substring(url.IndexOf("/Lists"));
url = url.Remove(url.IndexOf(";#"));
switch (oListItem["Feature_x0020_Order"].ToString())
{
case "1":
image1.ImageUrl = url;
break;
case "2":
image2.ImageUrl = url;
break;
case "3":
image3.ImageUrl = url;
break;
default:
//ERROR
break;
}
}
if (!(Page.IsPostBack))
{
image1.Visible = true;
image2.Visible = false;
image3.Visible = false;
}
imageUpdatePanel.ContentTemplateContainer.Controls.Add(image1);
imageUpdatePanel.ContentTemplateContainer.Controls.Add(image2);
imageUpdatePanel.ContentTemplateContainer.Controls.Add(image3);
//Create animation for update panel
upAnimator = new UpdatePanelAnimationExtender();
upAnimator.ID = "upAnimator";
upAnimator.TargetControlID = imageUpdatePanel.ID;
const string xml = "<OnUpdating>" +
"<Parallel duration=\".25\" Fps=\"30\">" +
"<FadeOut AnimationTarget=\"updateContainer\" minimumOpacity=\".2\" />" +
"</OnUpdating>" +
"<OnUpdated>" +
"<FadeIn AnimationTarget=\"updateContainer\" minimumOpacity=\".2\" />" +
"</OnUpdated>";
Animation.Parse(xml, upAnimator);
this.Controls.Add(upAnimator);
Button b1 = new Button();
b1.ID = "b1i";
b1.Click += new EventHandler(b1_Click);
b1.Text = "Image 1";
Button b2 = new Button();
b2.ID = "b2i";
b2.Click += new EventHandler(b2_Click);
b2.Text = "Image 2";
Button b3 = new Button();
b3.ID = "b3i";
b3.Click += new EventHandler(b3_Click);
b3.Text = "Image 3";
this.Controls.Add(b1);
this.Controls.Add(b2);
this.Controls.Add(b3);
AsyncPostBackTrigger tr1 = new AsyncPostBackTrigger();
tr1.ControlID = b1.ID;
//tr1.EventName = "Click";
imageUpdatePanel.Triggers.Add(tr1);
AsyncPostBackTrigger tr2 = new AsyncPostBackTrigger();
tr2.ControlID = b2.ID;
//tr2.EventName = "Click";
imageUpdatePanel.Triggers.Add(tr2);
AsyncPostBackTrigger tr3 = new AsyncPostBackTrigger();
tr3.ControlID = b3.ID;
//tr3.EventName = "Click";
imageUpdatePanel.Triggers.Add(tr3);
}
}
catch (Exception ex)
{
HandleException(ex);
}
}
}
void b1_Click(object sender, EventArgs e)
{
image1.Visible = true;
image2.Visible = false;
image3.Visible = false;
}
void b2_Click(object sender, EventArgs e)
{
image1.Visible = false;
image2.Visible = true;
image3.Visible = false;
}
void b3_Click(object sender, EventArgs e)
{
image1.Visible = false;
image2.Visible = false;
image3.Visible = true;
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
}
/// <summary>
/// Ensures that the CreateChildControls() is called before events.
/// Use CreateChildControls() to create your controls.
/// </summary>
/// <param name="e"></param>
protected override void OnLoad(EventArgs e)
{
if (!_error)
{
try
{
base.OnLoad(e);
this.EnsureChildControls();
// Your code here...
}
catch (Exception ex)
{
HandleException(ex);
}
}
}
/// <summary>
/// Clear all child controls and add an error message for display.
/// </summary>
/// <param name="ex"></param>
private void HandleException(Exception ex)
{
this._error = true;
this.Controls.Clear();
this.Controls.Add(new LiteralControl(ex.Message));
}
} }
Here's a related question though being asked in the context of SP 2010, it's still directly applicable given the solution.
We have a CQWP on our MOSS farm that does essentially the same thing: reads items from a list using jQuery and the SPServices plugin and animates slider changes. The most difficult part of the process is actually tweaking the look, if I remember correctly. Once you have the right pieces, putting it together is a snap.